home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / DeviceView / didevimg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  95.2 KB  |  2,856 lines

  1. //-----------------------------------------------------------------------------
  2. // File: DIDevImg.cpp
  3. //
  4. // Desc: Implementation for CDIDevImage class, which encapsulates methods for 
  5. //       drawing device images, callout strings, and object highlights.
  6. //
  7. // Copyright( c ) Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #include "DIDevImg.h"
  10. #include <d3dx9tex.h>
  11.  
  12.  
  13.  
  14. //-----------------------------------------------------------------------------
  15. // Name: CDIDevImage
  16. // Desc: Constructor
  17. //-----------------------------------------------------------------------------
  18. CDIDevImage::CDIDevImage() 
  19. {
  20.     m_bInitialized  = FALSE;
  21.     m_bCustomUI     = FALSE;
  22.     m_bInvalidUI    = TRUE;
  23.     m_ahImages      = NULL;
  24.     m_dwNumViews    = 0;
  25.     m_dwNumObjects  = 0;
  26.     m_apObject      = NULL;
  27.     m_dwWidthPref   = 0;
  28.     m_dwHeightPref  = 0;
  29.     m_dwScaleMethod = 0;
  30.     m_BkColor       = D3DCOLOR_ARGB(255, 0, 0, 0);
  31.     m_hFont         = NULL;
  32. }
  33.  
  34.  
  35.  
  36.  
  37. //-----------------------------------------------------------------------------
  38. // Name: ~CDIDevImage
  39. // Desc: Destructor
  40. //-----------------------------------------------------------------------------
  41. CDIDevImage::~CDIDevImage()
  42. {
  43.     CleanUp();
  44. }
  45.  
  46.  
  47.  
  48.  
  49. //-----------------------------------------------------------------------------
  50. // Name: Init
  51. // Desc: Responsible for initializing and preparing the CDIDevImage object for
  52. //       rendering the device image. Init must be called before the other
  53. //       public functions.
  54. // Args: pDIDevice - Pointer to a DirectInputDevice object for which the
  55. //         configuration UI should be created.
  56. //  Ret: DI_OK - Success; image found.
  57. //       DI_IMAGENOTFOUND - Success; no image. Default UI created instead.
  58. //       DIERR_INVALIDPARAM - Fail; invalid argument passed.
  59. //-----------------------------------------------------------------------------    
  60. HRESULT CDIDevImage::Init( LPDIRECTINPUTDEVICE8 pDIDevice )
  61. {
  62.     HRESULT hr = DI_OK;
  63.     
  64.     // Sanity check
  65.     if( NULL == pDIDevice )
  66.         return DIERR_INVALIDPARAM;
  67.  
  68.     // Always start clean
  69.     CleanUp();
  70.     
  71.     // retrieve the image info from DirectInput
  72.     hr = LoadImageInfo( pDIDevice );
  73.     if( FAILED(hr) )
  74.     {
  75.         // Image information may have partially loaded. Clean out whatever
  76.         // is stored since we'll need to create a custom UI from scratch.
  77.         CleanUp();
  78.  
  79.  
  80.         // For one reason or another, the image info for this device
  81.         // could not be loaded. At this point, create a default UI.
  82.         m_bCustomUI = true;
  83.         hr = CreateCustomImageInfo( pDIDevice );
  84.         if( FAILED(hr) )
  85.         {
  86.             SAFE_RELEASE(pDIDevice);
  87.             CleanUp();
  88.             return hr;
  89.         }
  90.     }
  91.     
  92.     // Create the default callout font
  93.     CreateFont();
  94.  
  95.     // Made it through initialization. Set the initialized flag to allow the
  96.     // other member functions to be called.
  97.     m_bInitialized = true;
  98.  
  99.     // Both of these values indicate success, but the client may wish to know
  100.     // whether an image was actually found for this device, or if we are just
  101.     // producing a default UI.
  102.     return m_bCustomUI ? DI_IMAGENOTFOUND : DI_OK;
  103. }
  104.  
  105.  
  106.  
  107.  
  108. //-----------------------------------------------------------------------------
  109. // Name: SetCalloutState
  110. // Desc: Sets the state for a specific callout
  111. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  112. //         dwType value returned by EnumDeviceObjects.
  113. //       dwCalloutState - New state of the callout, which may be zero or more
  114. //         combinations of:
  115. //         DIDICOS_HIGHLIGHTED - Overlay drawn. Callout drawn in high color.
  116. //         DIDICOS_INVISIBLE - Overlay and callout string not drawn.
  117. //         DIDICOS_TOOLTIP - Tooltip drawn if callout text is truncated.
  118. //  Ret: DI_OK - Success.
  119. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  120. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  121. //-----------------------------------------------------------------------------
  122. HRESULT CDIDevImage::SetCalloutState( DWORD dwObjId, DWORD dwCalloutState )
  123. {
  124.     // Verify initialization
  125.     if( false == m_bInitialized )
  126.         return DIERR_NOTINITIALIZED;
  127.  
  128.     CDIDIObject* pObject = GetObject( dwObjId );
  129.     if( NULL == pObject )
  130.         return DIERR_OBJECTNOTFOUND;
  131.                  
  132.     DWORD dwOldState = pObject->GetCalloutState();
  133.     pObject->SetCalloutState( dwCalloutState );
  134.  
  135.     // This action might change the layout for the custom UI
  136.     if( m_bCustomUI &&
  137.         ( DIDICOS_INVISIBLE & dwOldState ||
  138.           DIDICOS_INVISIBLE & dwCalloutState ) )
  139.           m_bInvalidUI = TRUE;
  140.  
  141.     return DI_OK;
  142. }
  143.  
  144.  
  145.  
  146.  
  147. //-----------------------------------------------------------------------------
  148. // Name: GetCalloutState
  149. // Desc: Returns the state of a specific callout
  150. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  151. //         dwType value returned by EnumDeviceObjects.
  152. //       pdwCalloutState - Pointer to a variable which will contain the current
  153. //         callout value after a successful return.
  154. //  Ret: DI_OK - Success.
  155. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  156. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  157. //-----------------------------------------------------------------------------
  158. HRESULT CDIDevImage::GetCalloutState( DWORD dwObjId, LPDWORD pdwCalloutState )
  159. {
  160.     // Verify initialization
  161.     if( false == m_bInitialized )
  162.         return DIERR_NOTINITIALIZED;
  163.  
  164.     CDIDIObject* pObject = GetObject( dwObjId );
  165.     if( NULL == pObject )
  166.         return DIERR_OBJECTNOTFOUND;
  167.  
  168.     *pdwCalloutState = pObject->GetCalloutState();
  169.     return DI_OK;
  170. }
  171.  
  172.  
  173.  
  174.  
  175. //-----------------------------------------------------------------------------
  176. // Name: SetCalloutColors
  177. // Desc: Sets the callout-unique colors to be used when painting a specific
  178. //       callout
  179. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  180. //         dwType value returned by EnumDeviceObjects.
  181. //       crColorNormal - Foreground text color for callout strings in a normal
  182. //         state.
  183. //       crColorHigh - Foreground text color for callout strings in a
  184. //         highlighted state.
  185. //  Ret: DI_OK - Success.
  186. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  187. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  188. //-----------------------------------------------------------------------------
  189. HRESULT CDIDevImage::SetCalloutColors( DWORD dwObjId, COLORREF crColorNormal, COLORREF crColorHigh )
  190. {
  191.     // Verify initialization
  192.     if( false == m_bInitialized )
  193.         return DIERR_NOTINITIALIZED;
  194.  
  195.     CDIDIObject* pObject = GetObject( dwObjId );
  196.     if( NULL == pObject )
  197.         return DIERR_OBJECTNOTFOUND;
  198.  
  199.     pObject->SetCalloutColors( crColorNormal, crColorHigh );
  200.     return DI_OK;
  201. }
  202.  
  203.  
  204.  
  205.  
  206. //-----------------------------------------------------------------------------
  207. // Name: GetCalloutColors
  208. // Desc: Obtains the callout-unique colors used when painting a specific
  209. //       callout
  210. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  211. //         dwType value returned by EnumDeviceObjects.
  212. //       pcrColorNormal - Pointer to a COLORREF variable which will contain
  213. //         the normal callout color after a successful return. May be NULL.
  214. //       pcrColorHigh - Pointer to a COLORREF variable which will contain
  215. //         the highlight callout color after a successful return. May be NULL.
  216. //  Ret: DI_OK - Success.
  217. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  218. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  219. //-----------------------------------------------------------------------------
  220. HRESULT CDIDevImage::GetCalloutColors( DWORD dwObjId, LPCOLORREF pcrColorNormal, LPCOLORREF pcrColorHigh )
  221. {
  222.     // Verify initialization
  223.     if( false == m_bInitialized )
  224.         return DIERR_NOTINITIALIZED;
  225.  
  226.     CDIDIObject* pObject = GetObject( dwObjId );
  227.     if( NULL == pObject )
  228.         return DIERR_OBJECTNOTFOUND;
  229.  
  230.     pObject->GetCalloutColors( pcrColorNormal, pcrColorHigh );
  231.     return DI_OK;
  232. }
  233.  
  234.  
  235.  
  236.  
  237. //-----------------------------------------------------------------------------
  238. // Name: SetCalloutText
  239. // Desc: Sets the text associated with the callout specified by an object ID
  240. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  241. //         dwType value returned by EnumDeviceObjects.
  242. //       strText - New callout text.
  243. //  Ret: DI_OK - Success.
  244. //       DIERR_INVALIDPARAM - Fail; Null pointer passed.
  245. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  246. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  247. //-----------------------------------------------------------------------------
  248. HRESULT CDIDevImage::SetCalloutText( DWORD dwObjId, LPCTSTR strText )
  249. {
  250.     // Verify initialization
  251.     if( false == m_bInitialized )
  252.         return DIERR_NOTINITIALIZED;
  253.  
  254.     if( NULL == strText )
  255.         return DIERR_INVALIDPARAM;
  256.  
  257.     CDIDIObject* pObject = GetObject( dwObjId );
  258.     if( NULL == pObject )
  259.         return DIERR_OBJECTNOTFOUND;
  260.  
  261.     pObject->SetCalloutText( strText );
  262.  
  263.     // This action might change the layout for the custom UI
  264.     if( m_bCustomUI )
  265.         m_bInvalidUI = TRUE;
  266.  
  267.     return DI_OK;
  268. }
  269.  
  270.  
  271.  
  272.  
  273. //-----------------------------------------------------------------------------
  274. // Name: GetCalloutText
  275. // Desc: Returns the text associated with a specific callout
  276. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  277. //         dwType value returned by EnumDeviceObjects.
  278. //       pstrText - Pointer to a string buffer which will collect the current
  279. //         callout string.
  280. //       dwSize - Maximum number of characters to copy into the buffer.
  281. //  Ret: DI_OK - Success.
  282. //       DIERR_INVALIDPARAM - Fail; Null pointer passed.
  283. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  284. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  285. //-----------------------------------------------------------------------------
  286. HRESULT CDIDevImage::GetCalloutText( DWORD dwObjId, LPTSTR pstrText, DWORD dwSize )
  287. {
  288.     // Verify initialization
  289.     if( false == m_bInitialized )
  290.         return DIERR_NOTINITIALIZED;
  291.  
  292.     if( NULL == pstrText )
  293.         return DIERR_INVALIDPARAM;
  294.  
  295.     CDIDIObject* pObject = GetObject( dwObjId );
  296.     if( NULL == pObject )
  297.         return DIERR_OBJECTNOTFOUND;
  298.  
  299.     pObject->GetCalloutText( pstrText, dwSize );
  300.  
  301.     return DI_OK;
  302. }
  303.  
  304.  
  305.  
  306.  
  307. //-----------------------------------------------------------------------------
  308. // Name: GetObjFromPoint
  309. // Desc: Returns the ID of the object on the device corresponding to the
  310. //       callout which contains the given point.
  311. // Args: Pt - Point to check against callout rect coordinates
  312. //       pdwObjId - Pointer to a variable which will contain the object ID upon
  313. //         successful return.
  314. //  Ret: DI_OK - Success.
  315. //       DIERR_INVALIDPARAM - Fail; Null pointer passed.
  316. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  317. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  318. //-----------------------------------------------------------------------------
  319. HRESULT CDIDevImage::GetObjFromPoint( POINT Pt, LPDWORD pdwObjId )
  320. {
  321.     // Verify initialization
  322.     if( false == m_bInitialized )
  323.         return DIERR_NOTINITIALIZED;
  324.  
  325.     if( NULL == pdwObjId )
  326.         return DIERR_INVALIDPARAM;
  327.  
  328.     if( m_dwActiveView > m_dwNumViews )
  329.         return E_FAIL;
  330.  
  331.     // For a custom UI, this method depends on the UI being calculated
  332.     if( m_bCustomUI && m_bInvalidUI )
  333.         BuildCustomUI();
  334.  
  335.     DIDICallout *pCallout = NULL;
  336.  
  337.     // for each object
  338.     for( UINT i=0; i < m_dwNumObjects; i++ )
  339.     {
  340.         pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
  341.         if( PtInRect( &(pCallout->rcScaled), Pt ) )
  342.         {
  343.             // if the point is inside the scaled bounding rect, the
  344.             // correct callout has been found.
  345.             *pdwObjId = m_apObject[i]->GetID();
  346.             return DI_OK;
  347.         }
  348.     }
  349.  
  350.     return S_FALSE;
  351. }
  352.  
  353.  
  354.  
  355.  
  356. //-----------------------------------------------------------------------------
  357. // Name: SetActiveView
  358. // Desc: Activates the provided view. This view will be painted when the 
  359. //       device image is rendered.
  360. // Args: dwView - The index of the new view.
  361. //  Ret: DI_OK - Success.
  362. //       DIERR_INVALIDPARAM - Fail; View is out of range.
  363. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  364. //-----------------------------------------------------------------------------
  365. HRESULT CDIDevImage::SetActiveView( DWORD dwView )
  366. {
  367.     // Verify initialization
  368.     if( false == m_bInitialized )
  369.         return DIERR_NOTINITIALIZED;
  370.  
  371.     // For a custom UI, this method depends on the UI being calculated
  372.     if( m_bCustomUI && m_bInvalidUI )
  373.         BuildCustomUI();
  374.  
  375.     // Make sure view exists
  376.     if( dwView >= m_dwNumViews )
  377.         return DIERR_INVALIDPARAM;
  378.  
  379.     m_dwActiveView = dwView;
  380.     return DI_OK;
  381. }
  382.  
  383.  
  384.  
  385.  
  386. //-----------------------------------------------------------------------------
  387. // Name: GetActiveView
  388. // Desc: Returns the index of the currently active view. The active view is
  389. //       what CDIDevImage paints when the device image is rendered.
  390. // Args: pdwView - Pointer to a variable which will contain the current view
  391. //         index upon successful return. May be NULL.
  392. //       pdwNumViews - Pointer to a variable which will contain the total
  393. //         number of views upon successful return. May be NULL.
  394. //  Ret: DI_OK - Success.
  395. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  396. //-----------------------------------------------------------------------------
  397. HRESULT CDIDevImage::GetActiveView( LPDWORD pdwView, LPDWORD pdwNumViews )
  398. {
  399.     // Verify initialization
  400.     if( false == m_bInitialized )
  401.         return DIERR_NOTINITIALIZED;
  402.  
  403.     // For a custom UI, this method depends on the UI being calculated
  404.     if( m_bCustomUI && m_bInvalidUI )
  405.         BuildCustomUI();
  406.  
  407.     if( pdwView )
  408.         *pdwView = m_dwActiveView;
  409.  
  410.     if( pdwNumViews )
  411.         *pdwNumViews = m_dwNumViews;
  412.  
  413.     return DI_OK;
  414. }
  415.  
  416.  
  417.  
  418.  
  419. //-----------------------------------------------------------------------------
  420. // Name: GetViewForObj
  421. // Desc: Returns the index of the most appropriate view for a specific object
  422. // Args: dwObjId - Object ID of the requested callout. This corresponds to the
  423. //         dwType value returned by EnumDeviceObjects.
  424. //       pdwView - Pointer to a variable which will contain an appropriate
  425. //         view for the given object after return. May be NULL.
  426. //  Ret: DI_OK - Success.
  427. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  428. //       DIERR_INVALIDPARAM - Fail; Null pointer.
  429. //       DIERR_OBJECTNOTFOUND - Fail; Given ID not found in list of objects
  430. //-----------------------------------------------------------------------------
  431. HRESULT CDIDevImage::GetViewForObj( DWORD dwObjId, LPDWORD pdwView )
  432. {
  433.     UINT i=0; // Loop variable
  434.  
  435.     // Verify initialization
  436.     if( false == m_bInitialized )
  437.         return DIERR_NOTINITIALIZED;
  438.  
  439.     if( NULL == pdwView )
  440.         return DIERR_INVALIDPARAM;
  441.  
  442.     CDIDIObject* pObject = GetObject( dwObjId );
  443.     if( NULL == pObject )
  444.         return DIERR_OBJECTNOTFOUND;
  445.  
  446.     // For a custom UI, this method depends on the UI being calculated
  447.     if( m_bCustomUI && m_bInvalidUI )
  448.         BuildCustomUI();
  449.  
  450.     // The method used to determine the best view for a particular object
  451.     // is simple: The view which has the largest overlay rectangle probably
  452.     // has the best view for an object. If there are no overlays for the
  453.     // given object, use the view with the largest callout rectangle, or
  454.     // the base view (0) if there are no callouts for the given object.
  455.     
  456.     DWORD dwCalloutMax = 0;
  457.     DWORD dwCalloutIndex = 0;
  458.  
  459.     DWORD dwOverlayMax = 0;
  460.     DWORD dwOverlayIndex = 0;
  461.  
  462.     for( i=0; i < m_dwNumViews; i++ )
  463.     {
  464.         DWORD dwArea = 0;
  465.  
  466.         DIDIOverlay *pOverlay = pObject->GetOverlay( i );
  467.         DIDICallout *pCallout = pObject->GetCallout( i );
  468.  
  469.         dwArea = ( pOverlay->rcScaled.right - pOverlay->rcScaled.left ) *
  470.                  ( pOverlay->rcScaled.bottom - pOverlay->rcScaled.top );
  471.  
  472.         if( dwArea > dwOverlayMax )
  473.         {
  474.             dwOverlayMax = dwArea;
  475.             dwOverlayIndex = i;
  476.         }      
  477.  
  478.         dwArea = ( pCallout->rcScaled.right - pCallout->rcScaled.left ) *
  479.                  ( pCallout->rcScaled.bottom - pCallout->rcScaled.top );
  480.  
  481.         if( dwArea > dwCalloutMax )
  482.         {
  483.             dwCalloutMax = dwArea;
  484.             dwCalloutIndex = i;
  485.         }      
  486.     }
  487.     
  488.     // If an overlay rectangle was found, use the overlay index; otherwise,
  489.     // use the callout index (this will be 0 if no callouts were found ).
  490.     *pdwView = ( dwOverlayMax > 0 ) ? dwOverlayIndex : dwCalloutIndex;
  491.     
  492.     return DI_OK;
  493. }
  494.  
  495.  
  496.  
  497.  
  498. //-----------------------------------------------------------------------------
  499. // Name: SetOutputImageSize
  500. // Desc: Sets the size of the image that CDIDevImage will paint and output to
  501. //       the application
  502. // Args: dwWidth - Preferred width.
  503. //       dwHeight - Preferred height.
  504. //       dwFlags - Scaling flag. Must be one of following:
  505. //         DIDISOIS_DEFAULT - dwWidth and dwHeight values are ignored. The image
  506. //           will not be scaled after loaded from disk; for created UIs, the
  507. //           size is determined by the global constants. This is the default
  508. //           value.                 
  509. //         DIDISOIS_RESIZE - Scale the image and callouts to the given width
  510. //           and height.
  511. //         DIDISOIS_MAINTAINASPECTUSINGWIDTH - Scale the image and callouts to
  512. //           the given width, but maintain the aspect ratio. The dwHeight 
  513. //           argument is ignored
  514. //         DIDISOIS_MAINTAINASPECTUSINGHEIGHT - Scale the image and callouts to
  515. //           the given height, but maintain the aspect ratio. The dwWidth
  516. //           argument is ignored.
  517. //  Ret: DI_OK - Success.
  518. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  519. //-----------------------------------------------------------------------------
  520. HRESULT CDIDevImage::SetOutputImageSize( DWORD dwWidth, DWORD dwHeight, DWORD dwFlags )
  521. {
  522.     // Verify initialization
  523.     if( false == m_bInitialized )
  524.         return DIERR_NOTINITIALIZED;
  525.  
  526.     // Store arguments
  527.     m_dwWidthPref   = dwWidth;
  528.     m_dwHeightPref  = dwHeight;
  529.     m_dwScaleMethod = dwFlags;
  530.  
  531.     // If the image size has changed, all the stored images are no longer valid
  532.     DestroyImages();
  533.  
  534.     // This action might change the layout for the custom UI
  535.     if( m_bCustomUI )
  536.         m_bInvalidUI = TRUE;
  537.  
  538.     return DI_OK;
  539. }
  540.  
  541.  
  542.  
  543.  
  544. //-----------------------------------------------------------------------------
  545. // Name: SetFont
  546. // Desc: Sets the font to be used for the callout text when rendering the image
  547. // Args: hFont - Handle to a GDI font object. The font's properties will be
  548. //         copied and used for drawn text.
  549. //  Ret: DI_OK - Success.
  550. //       DIERR_INVALIDPARAM - Fail; Invalid handle.
  551. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  552. //-----------------------------------------------------------------------------
  553. HRESULT CDIDevImage::SetFont( HFONT hFont )
  554. {
  555.     LOGFONT logfont = {0};
  556.     HFONT   hNewFont   = NULL;
  557.  
  558.     // Verify initialization
  559.     if( false == m_bInitialized )
  560.         return DIERR_NOTINITIALIZED;
  561.  
  562.     // Retrieve the logfont and create a new member font
  563.     if( 0 == ::GetObject( hFont, sizeof(LOGFONT), &logfont ) )
  564.         return DIERR_INVALIDPARAM;
  565.  
  566.     // Create a duplicate font
  567.     hNewFont = CreateFontIndirect( &logfont );
  568.     if( NULL == hNewFont )
  569.         return E_FAIL;
  570.  
  571.     // Remove the current font
  572.     if( m_hFont )
  573.         DeleteObject( m_hFont );
  574.  
  575.     // Copy the font handle
  576.     m_hFont = hNewFont;
  577.  
  578.     // This action might change the layout for the custom UI
  579.     if( m_bCustomUI )
  580.         m_bInvalidUI = TRUE;
  581.  
  582.     return DI_OK;
  583. }
  584.  
  585.  
  586.  
  587.  
  588. //-----------------------------------------------------------------------------
  589. // Name: SetColors
  590. // Desc: Assigns a set of colors to use when painting the various items on the
  591. //       image
  592. // Args: Background - Specifies the color and alpha component for the
  593. //         image background. Device images are stored in a format which allows
  594. //         the background to be replaced. D3D surfaces allow this background
  595. //         to contain transparency information. Alpha values of 0 thru 254 allow
  596. //         varying transparency effects on the output surfaces. A value
  597. //         of 255 is treated specially during alpha blending, such that the 
  598. //         final output image will fully opaque.
  599. //       crColorNormal - Foreground text color for callout strings in a normal
  600. //         state.
  601. //       crColorHigh - Foreground text color for callout strings in a
  602. //         highlighted state.
  603. //  Ret: DI_OK - Success.
  604. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  605. //-----------------------------------------------------------------------------
  606. HRESULT CDIDevImage::SetColors( D3DCOLOR Background, COLORREF crCalloutNormal, COLORREF crCalloutHigh )
  607. {
  608.     // Verify initialization
  609.     if( false == m_bInitialized )
  610.         return DIERR_NOTINITIALIZED;
  611.  
  612.     // If the background is changing colors, the images will have to be 
  613.     // reloaded. As an optimization, the background color is only applied
  614.     // when the image is loaded since the background won't change as often as
  615.     // the image is rendered.
  616.     if( m_BkColor != Background )
  617.         DestroyImages();
  618.     
  619.     m_BkColor = Background;
  620.  
  621.     for( UINT i=0; i < m_dwNumObjects; i++ )
  622.     {
  623.         m_apObject[i]->SetCalloutColors( crCalloutNormal, crCalloutHigh );
  624.     }
  625.  
  626.     return DI_OK;
  627. }
  628.  
  629.  
  630.  
  631.  
  632. //-----------------------------------------------------------------------------
  633. // Name: Render
  634. // Desc: Renders an image of the device and its callouts onto a Direct3DTexture
  635. // Args: pTexture - Pointer to a D3D Texture Object on which to paint the UI.
  636. //  Ret: DI_OK - Success.
  637. //       DIERR_INVALIDPARAM - Fail; Null pointer.
  638. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  639. //-----------------------------------------------------------------------------
  640. HRESULT CDIDevImage::Render( LPDIRECT3DTEXTURE9 pTexture )
  641. {
  642.     HRESULT hr = DI_OK;
  643.     LPDIRECT3DSURFACE9 pSurface = NULL;
  644.  
  645.     // Verify initialization
  646.     if( false == m_bInitialized )
  647.         return DIERR_NOTINITIALIZED;
  648.  
  649.     // Check parameters
  650.     if( NULL == pTexture )
  651.         return DIERR_INVALIDPARAM;
  652.  
  653.     // Add a reference to the passed texture
  654.     pTexture->AddRef();
  655.  
  656.     // Extract the surface
  657.     hr = pTexture->GetSurfaceLevel( 0, &pSurface );
  658.     if( FAILED(hr) )
  659.         goto LCleanReturn;
  660.  
  661.     // Perform the render
  662.     if( m_bCustomUI )
  663.         hr = RenderCustomToTarget( (LPVOID) pSurface, DIDIRT_SURFACE );
  664.     else
  665.         hr = RenderToTarget( (LPVOID) pSurface, DIDIRT_SURFACE );
  666.  
  667.  
  668. LCleanReturn:
  669.  
  670.     SAFE_RELEASE( pSurface );
  671.     SAFE_RELEASE( pTexture );
  672.     return hr;
  673. }
  674.  
  675.  
  676.  
  677.  
  678. //-----------------------------------------------------------------------------
  679. // Name: RenderToDC
  680. // Desc: Renders an image of the device and its callouts onto a GDI device
  681. //       object
  682. // Args: hDC - Handle to a device context on which to paint the UI.
  683. //  Ret: DI_OK - Success.
  684. //       DIERR_NOTINITIALIZED - Fail; Init() must be called first.
  685. //-----------------------------------------------------------------------------
  686. HRESULT CDIDevImage::RenderToDC( HDC hDC )
  687. {
  688.     HRESULT hr = S_OK;
  689.  
  690.     // Verify initialization
  691.     if( false == m_bInitialized )
  692.         return DIERR_NOTINITIALIZED;
  693.  
  694.     if( m_bCustomUI )
  695.         hr = RenderCustomToTarget( (LPVOID) hDC, DIDIRT_DC );
  696.     else
  697.         hr = RenderToTarget( (LPVOID) hDC, DIDIRT_DC );
  698.  
  699.     return hr;
  700. }
  701.  
  702.  
  703.  
  704.  
  705. //-----------------------------------------------------------------------------
  706. // Name: RenderCustomToTarget
  707. // Desc: Renders a custom UI
  708. //-----------------------------------------------------------------------------
  709. HRESULT CDIDevImage::RenderCustomToTarget( LPVOID pvTarget, DIDIRENDERTARGET eTarget )
  710. {
  711.     HRESULT    hr         = DI_OK;
  712.     UINT       i          = 0;
  713.     HDC        hdcRender  = NULL;
  714.     HDC        hdcAlpha   = NULL;
  715.     RECT       rcBitmap   = {0};
  716.     DIBSECTION info       = {0};
  717.     HBITMAP    hbmpRender = NULL;
  718.     HBITMAP    hbmpAlpha  = NULL;
  719.     SIZE       size       = {0};
  720.  
  721.     // Get the UI dimensions
  722.     GetCustomUISize( &size );
  723.  
  724.     if( m_bInvalidUI )
  725.         BuildCustomUI();
  726.  
  727.     // Create a background image
  728.     BITMAPINFO bmi = {0};
  729.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  730.     bmi.bmiHeader.biWidth = size.cx;
  731.     bmi.bmiHeader.biHeight = - (int) size.cy; // top-down
  732.     bmi.bmiHeader.biPlanes = 1;
  733.     bmi.bmiHeader.biBitCount = 32;
  734.     bmi.bmiHeader.biCompression = BI_RGB;
  735.  
  736.     hdcRender = CreateCompatibleDC( NULL );
  737.     if( NULL == hdcRender )
  738.     {
  739.         hr = DIERR_OUTOFMEMORY;
  740.         goto LCleanReturn;
  741.     }
  742.  
  743.     hdcAlpha = CreateCompatibleDC( NULL );
  744.     if( NULL == hdcAlpha )
  745.     {
  746.         hr = DIERR_OUTOFMEMORY;
  747.         goto LCleanReturn;
  748.     }
  749.     
  750.     hbmpRender = CreateDIBSection( hdcRender, &bmi, DIB_RGB_COLORS, NULL, NULL, NULL );
  751.     if( hbmpRender == NULL )
  752.     {
  753.         hr = DIERR_OUTOFMEMORY;
  754.         goto LCleanReturn;
  755.     }
  756.  
  757.     if( 0 == ::GetObject( hbmpRender, sizeof( DIBSECTION ), &info ) )
  758.     {
  759.         hr = E_FAIL;
  760.         goto LCleanReturn;
  761.     }
  762.  
  763.     
  764.     SelectObject( hdcRender, hbmpRender );
  765.     SelectObject( hdcRender, m_hFont );
  766.     SetBkMode( hdcRender, TRANSPARENT );
  767.  
  768.     FillBackground( hbmpRender, m_BkColor );
  769.  
  770.     // Create a bitmap to store the alpha channel for the bitmap. Since GDI
  771.     // doesn't support alpha information, everything is drawn fully transparent.
  772.     // As a workaround, whenever a 2D method is called on the render dc,
  773.     // the same method will be called on the alpha dc. Before transfering the
  774.     // image to the provided surface, the transparency information will be 
  775.     // restored from the alpha bitmap. 
  776.     hbmpAlpha = CreateDIBSection( hdcAlpha, &bmi, DIB_RGB_COLORS, NULL, NULL, NULL );
  777.     if( NULL == hbmpAlpha )
  778.     {
  779.         hr = DIERR_OUTOFMEMORY;
  780.         goto LCleanReturn;
  781.     }
  782.  
  783.     // Clear the alpha channel
  784.     DIBSECTION infoAlpha;
  785.     if( 0 == ::GetObject( hbmpAlpha, sizeof(DIBSECTION), &infoAlpha ) )
  786.     {
  787.         hr = E_FAIL;
  788.         goto LCleanReturn;
  789.     }
  790.     ZeroMemory( infoAlpha.dsBm.bmBits, infoAlpha.dsBm.bmWidthBytes * infoAlpha.dsBm.bmHeight );
  791.  
  792.     SelectObject( hdcAlpha, hbmpAlpha );
  793.  
  794.     SetBkMode( hdcAlpha, TRANSPARENT );
  795.     SetTextColor( hdcAlpha, RGB(255, 255, 255) );
  796.     SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) );
  797.     SelectObject( hdcAlpha, m_hFont );
  798.         
  799.  
  800.     // Draw callout and object text
  801.     for( i=0; i < m_dwNumObjects; i++ )
  802.     {
  803.         COLORREF crNorm, crHigh, crCur;
  804.         
  805.         DIDICallout *pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
  806.         DIDIOverlay *pOverlay = m_apObject[i]->GetOverlay( m_dwActiveView );
  807.  
  808.         MAXSTRING    strCallout = {0};
  809.         MAXSTRING    strObject  = {0};
  810.  
  811.         RECT rcFill = {0};
  812.         
  813.         // Callout may be invisible
  814.         if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
  815.             continue;
  816.  
  817.         if( IsRectEmpty( &pOverlay->rcScaled ) ||
  818.             IsRectEmpty( &pCallout->rcScaled ) )
  819.             continue;
  820.  
  821.         m_apObject[i]->GetCalloutText( strCallout, MAX_PATH );
  822.         m_apObject[i]->GetName( strObject, MAX_PATH );
  823.         m_apObject[i]->GetCalloutColors( &crNorm, &crHigh );
  824.  
  825.         crCur = ( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() ) ? crHigh : crNorm;
  826.         
  827.         SetTextColor( hdcRender, crNorm );
  828.         
  829.         DWORD dwFlags = DT_TOP | DT_END_ELLIPSIS | DT_NOCLIP;
  830.  
  831.         // Get the fill rect
  832.         rcFill = pOverlay->rcScaled;
  833.         DrawText( hdcRender, strObject, lstrlen( strObject ),
  834.                   &rcFill, dwFlags | DT_CALCRECT );
  835.  
  836.         // Position the fill rect
  837.         rcFill.left += pOverlay->rcScaled.right - rcFill.right;
  838.         rcFill.right += pOverlay->rcScaled.right - rcFill.right;
  839.  
  840.         // Inflate the fill rect
  841.         InflateRect( &rcFill, 5, 5 );
  842.  
  843.         // But make sure the rect still fits on the screen
  844.         rcFill.left   = max( rcFill.left,   0 );
  845.         rcFill.top    = max( rcFill.top,    0 );
  846.         rcFill.right  = min( rcFill.right,  info.dsBm.bmWidth );
  847.         rcFill.bottom = min( rcFill.bottom, info.dsBm.bmHeight );
  848.  
  849.         // Draw the object text
  850.         DrawText( hdcRender, strObject, lstrlen( strObject ),
  851.                   &(pOverlay->rcScaled), dwFlags | DT_RIGHT );
  852.  
  853.         if( hdcAlpha )
  854.             DrawText( hdcAlpha, strObject, lstrlen( strObject ),
  855.                       &(pOverlay->rcScaled), dwFlags | DT_RIGHT );
  856.         
  857.         SetTextColor( hdcRender, crCur );
  858.         
  859.         // Get the fill rect
  860.         rcFill = pCallout->rcScaled;
  861.         DrawText( hdcRender, strCallout, lstrlen( strCallout ),
  862.                   &rcFill, dwFlags | DT_CALCRECT );
  863.  
  864.         // Inflate the fill rect
  865.         InflateRect( &rcFill, 5, 5 );
  866.  
  867.         // But make sure the rect still fits on the screen
  868.         rcFill.left   = max( rcFill.left,   0 );
  869.         rcFill.top    = max( rcFill.top,    0 );
  870.         rcFill.right  = min( rcFill.right,  info.dsBm.bmWidth );
  871.         rcFill.bottom = min( rcFill.bottom, info.dsBm.bmHeight );
  872.  
  873.         // Draw the callout text
  874.         DrawText( hdcRender, strCallout, lstrlen( strCallout ),
  875.                   &(pCallout->rcScaled), dwFlags | DT_LEFT );
  876.  
  877.         if( hdcAlpha )
  878.             DrawText( hdcAlpha, strCallout, lstrlen( strCallout ),
  879.                       &(pCallout->rcScaled), dwFlags | DT_LEFT );
  880.  
  881.         // If the TOOLTIP flag is set and the callout text doesn't fit within
  882.         // the scaled rect, we need to draw the full text
  883.         if( DIDICOS_TOOLTIP & m_apObject[i]->GetCalloutState() )
  884.         {
  885.             SIZE TextSize = {0};
  886.             
  887.             // This string was modified by the first call to draw text, so we
  888.             // need to get a fresh copy
  889.             m_apObject[i]->GetCalloutText( strCallout, MAX_PATH-4 );
  890.             GetTextExtentPoint32( hdcRender, strCallout, lstrlen( strCallout ), &TextSize );
  891.  
  892.             if( TextSize.cx > ( pCallout->rcScaled.right - pCallout->rcScaled.left ) )
  893.             {
  894.                 // Yep, the text is too big and is marked as a tooltip candidate.
  895.                 RECT rcBitmap = { 0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight };
  896.                 DrawTooltip( hdcRender, hdcAlpha, strCallout, &rcBitmap, &(pCallout->rcScaled),
  897.                              CRFromColor( m_BkColor ), crNorm, crHigh );
  898.                 
  899.             }
  900.  
  901.         }
  902.     }
  903.  
  904.     // Finalize rendering
  905.     GdiFlush();
  906.  
  907.     // Copy the freshly rendered image to the render target
  908.     switch( eTarget )
  909.     {
  910.         case DIDIRT_SURFACE:
  911.             // Since the image is being transfered to a Direct3D surface, the stored
  912.             // alpha information could be used.
  913.             ApplyAlphaChannel( hbmpRender, hbmpAlpha, ( (m_BkColor & ALPHA_MASK) == ALPHA_MASK ) );
  914.             rcBitmap.right  = info.dsBm.bmWidth;
  915.             rcBitmap.bottom = info.dsBm.bmHeight;
  916.  
  917.             hr = D3DXLoadSurfaceFromMemory( (LPDIRECT3DSURFACE9) pvTarget,
  918.                                              NULL, NULL, info.dsBm.bmBits,
  919.                                              D3DFMT_A8R8G8B8, 
  920.                                              info.dsBm.bmWidthBytes,
  921.                                              NULL, &rcBitmap, 
  922.                                              D3DX_FILTER_NONE, 0 );
  923.             break;
  924.  
  925.         case DIDIRT_DC:
  926.             BitBlt( (HDC) pvTarget, 0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight,
  927.                           hdcRender, 0, 0, SRCCOPY );
  928.  
  929.             break;
  930.     
  931.         default:
  932.             // Invalid render target
  933.             hr = DIERR_INVALIDPARAM;
  934.             goto LCleanReturn;
  935.     }   
  936.  
  937.  
  938. LCleanReturn:
  939.     
  940.     DeleteDC( hdcRender );
  941.     DeleteDC( hdcAlpha );
  942.     
  943.     if( hbmpAlpha )
  944.         DeleteObject( hbmpAlpha );
  945.  
  946.     if( hbmpRender )
  947.         DeleteObject( hbmpRender );
  948.  
  949.     return hr;
  950. }
  951.  
  952.  
  953.  
  954.  
  955. //-----------------------------------------------------------------------------
  956. // Name: RenderToTarget
  957. // Desc: Renders an image of the device and its callouts 
  958. //-----------------------------------------------------------------------------
  959. HRESULT CDIDevImage::RenderToTarget( LPVOID pvTarget, DIDIRENDERTARGET eTarget )
  960. {
  961.     HRESULT    hr           = DI_OK;
  962.     UINT       i            = 0; // Loop variable
  963.     RECT       rcBitmap     = {0};
  964.     HDC        hdcRender    = NULL;
  965.     HDC        hdcAlpha     = NULL;
  966.     DIBSECTION info         = {0};
  967.     
  968.     LPBYTE     pSavedPixels = NULL;
  969.     LPBYTE     pCleanPixels = NULL;
  970.     
  971.     HBITMAP    hbmpAlpha    = NULL;
  972.     BITMAPINFO bmi = {0};
  973.     
  974.     
  975.     // Verify initialization
  976.     if( false == m_bInitialized )
  977.         return DIERR_NOTINITIALIZED;
  978.  
  979.     // Verify parameters
  980.     if( NULL == pvTarget )
  981.         return DIERR_INVALIDPARAM;
  982.  
  983.     // Sanity check
  984.     if( m_dwActiveView >= m_dwNumViews )
  985.         return E_FAIL;
  986.  
  987.     // Load images if not loaded already
  988.     if( NULL == m_ahImages[ m_dwActiveView ] )
  989.     {  
  990.         // File UI not yet loaded
  991.         if( FAILED( hr = LoadImages() ) )
  992.             return hr;
  993.     } 
  994.     
  995.  
  996.     // Get information about the background image.
  997.     if( 0 == ::GetObject( m_ahImages[ m_dwActiveView ], sizeof(DIBSECTION), &info ) )
  998.         return E_FAIL;
  999.  
  1000.  
  1001.     // Allocate space for the saved background images
  1002.     pSavedPixels = new BYTE[ info.dsBm.bmWidthBytes * info.dsBm.bmHeight ];
  1003.     if( NULL == pSavedPixels )
  1004.     {
  1005.         hr = DIERR_OUTOFMEMORY;
  1006.         goto LCleanReturn;
  1007.     }
  1008.  
  1009.     pCleanPixels = new BYTE[ info.dsBm.bmWidthBytes * info.dsBm.bmHeight ];
  1010.     if( NULL == pCleanPixels )
  1011.     {
  1012.         // Could not create a copy of the background image; release memory
  1013.         // here to avoid using unitialized pixels during cleanup.
  1014.         SAFE_DELETE_ARRAY( pSavedPixels );
  1015.  
  1016.         hr = DIERR_OUTOFMEMORY; 
  1017.         goto LCleanReturn;
  1018.     }
  1019.  
  1020.     // Save the background
  1021.     CopyMemory( pSavedPixels, info.dsBm.bmBits, 
  1022.                 info.dsBm.bmWidthBytes * info.dsBm.bmHeight );
  1023.     
  1024.     // Draw overlays
  1025.     for( i=0; i < m_dwNumObjects; i++ )
  1026.     {  
  1027.         DIDIOverlay *pOverlay = m_apObject[i]->GetOverlay( m_dwActiveView );
  1028.         
  1029.         if( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() )
  1030.         {     
  1031.             // Draw overlay
  1032.             if( pOverlay->hImage )    
  1033.                 ApplyOverlay( m_ahImages[ m_dwActiveView ], &pOverlay->rcScaled, pOverlay->hImage );      
  1034.         }
  1035.     }
  1036.  
  1037.     // Before drawing callouts and lines on top of the composed image, save
  1038.     // a copy of the image bits. This will allow us to erase portions of lines
  1039.     // which intersect with the callout text.
  1040.     CopyMemory( pCleanPixels, info.dsBm.bmBits, 
  1041.                 info.dsBm.bmWidthBytes * info.dsBm.bmHeight );
  1042.   
  1043.     // Load the background image into a device context for rendering
  1044.     hdcRender = CreateCompatibleDC( NULL );
  1045.     SelectObject( hdcRender, m_ahImages[ m_dwActiveView ] );
  1046.     
  1047.     SelectObject( hdcRender, m_hFont );
  1048.     SetBkMode( hdcRender, TRANSPARENT );
  1049.     SetBkColor( hdcRender, CRFromColor(m_BkColor) );
  1050.   
  1051.     hdcAlpha = CreateCompatibleDC( NULL );
  1052.  
  1053.     // Create a bitmap to store the alpha channel for the bitmap. Since GDI
  1054.     // doesn't support alpha information, everything is drawn fully transparent.
  1055.     // As a workaround, whenever a 2D method is called on the render dc,
  1056.     // the same method will be called on the alpha dc. Before transfering the
  1057.     // image to the provided surface, the transparency information will be 
  1058.     // restored from the alpha bitmap. 
  1059.     
  1060.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1061.     bmi.bmiHeader.biWidth = info.dsBm.bmWidth;
  1062.     bmi.bmiHeader.biHeight = - (int) info.dsBm.bmHeight; // top-down
  1063.     bmi.bmiHeader.biPlanes = 1;
  1064.     bmi.bmiHeader.biBitCount = 32;
  1065.     bmi.bmiHeader.biCompression = BI_RGB;
  1066.  
  1067.     hbmpAlpha = CreateDIBSection( hdcAlpha, &bmi, DIB_RGB_COLORS, NULL, NULL, NULL );
  1068.     if( NULL == hbmpAlpha )
  1069.     {
  1070.         hr = DIERR_OUTOFMEMORY;
  1071.         goto LCleanReturn;
  1072.     }
  1073.  
  1074.     // Clear the alpha channel
  1075.     DIBSECTION infoAlpha;
  1076.     if( 0 == ::GetObject( hbmpAlpha, sizeof(DIBSECTION), &infoAlpha ) )
  1077.     {
  1078.         hr = E_FAIL;
  1079.         goto LCleanReturn;
  1080.     }
  1081.     ZeroMemory( infoAlpha.dsBm.bmBits, infoAlpha.dsBm.bmWidthBytes * infoAlpha.dsBm.bmHeight );
  1082.  
  1083.     SelectObject( hdcAlpha, hbmpAlpha );
  1084.  
  1085.     SetBkMode( hdcAlpha, TRANSPARENT );
  1086.     SetTextColor( hdcAlpha, RGB(255, 255, 255) );
  1087.     SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) );
  1088.     SelectObject( hdcAlpha, m_hFont );
  1089.      
  1090.  
  1091.     // Draw callout lines
  1092.     for( i=0; i < m_dwNumObjects; i++ )
  1093.     {
  1094.         COLORREF crNorm, crHigh, crCur;
  1095.         POINT    aptArrow[2] = {0}; 
  1096.         BOOL     bDrawArrow = FALSE;
  1097.         
  1098.         // Get the current callout
  1099.         DIDICallout *pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
  1100.  
  1101.         // Callout may be invisible
  1102.         if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
  1103.             continue;
  1104.         
  1105.         // Retrieve normal/highlighted colors
  1106.         m_apObject[i]->GetCalloutColors( &crNorm, &crHigh );
  1107.  
  1108.         // Set the current color based on callout state
  1109.         crCur = ( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() ) ? crHigh : crNorm;
  1110.        
  1111.  
  1112.         DeleteObject( SelectObject( hdcRender, CreatePen( PS_SOLID, 3, CRFromColor(m_BkColor) ) ) ); 
  1113.         DeleteObject( SelectObject( hdcAlpha, CreatePen( PS_SOLID, 3, RGB(255, 255, 255) ) ) ); 
  1114.  
  1115.         // Draw callout lines
  1116.         MoveToEx( hdcRender, pCallout->aptLineScaled[0].x, pCallout->aptLineScaled[0].y, NULL );
  1117.         MoveToEx( hdcAlpha, pCallout->aptLineScaled[0].x, pCallout->aptLineScaled[0].y, NULL );
  1118.         
  1119.         for( UINT j=1; j < pCallout->dwNumPoints; j++ )
  1120.         {
  1121.             LineTo( hdcRender, pCallout->aptLineScaled[j].x, pCallout->aptLineScaled[j].y );
  1122.             LineTo( hdcAlpha, pCallout->aptLineScaled[j].x, pCallout->aptLineScaled[j].y );
  1123.         }
  1124.  
  1125.         // Draw arrow ends
  1126.         if( pCallout->dwNumPoints >= 2 )
  1127.         {
  1128.             DWORD dwEnd = pCallout->dwNumPoints-1;
  1129.             POINT p1 = pCallout->aptLineScaled[ dwEnd ];
  1130.             POINT p2 = pCallout->aptLineScaled[ dwEnd-1 ];
  1131.  
  1132.             aptArrow[0] = aptArrow[1] = p1;
  1133.             bDrawArrow = TRUE;
  1134.  
  1135.             aptArrow[0].x -= 1;
  1136.             aptArrow[0].y -= 1;
  1137.             aptArrow[1].x += 1;
  1138.             aptArrow[1].y += 1;
  1139.             
  1140.             // Adjust arrow points based on line orientation
  1141.             if( p1.y == p2.y )
  1142.             {
  1143.                 if( p2.x < p1.x )
  1144.                     aptArrow[1].x -= 2;
  1145.                 else
  1146.                     aptArrow[0].x += 2;
  1147.             }
  1148.             else if( p1.x == p2.x )
  1149.             {
  1150.                 if( p2.y < p1.y )
  1151.                     aptArrow[1].y -= 2;
  1152.                 else
  1153.                     aptArrow[0].y += 2;
  1154.             }
  1155.             else
  1156.             {
  1157.                 // This is a diagonal line. Skip the arrow endpoint.
  1158.                 bDrawArrow = FALSE;
  1159.             }
  1160.  
  1161.             if( bDrawArrow )
  1162.             {
  1163.                 MoveToEx( hdcRender, aptArrow[0].x, aptArrow[0].y, NULL );
  1164.                 LineTo(   hdcRender, aptArrow[1].x, aptArrow[1].y );
  1165.  
  1166.                 MoveToEx( hdcAlpha, aptArrow[0].x, aptArrow[0].y, NULL );
  1167.                 LineTo(   hdcAlpha, aptArrow[1].x, aptArrow[1].y );
  1168.             }
  1169.         }
  1170.  
  1171.         // Select a new pen into the DC based on current color
  1172.         DeleteObject( SelectObject( hdcRender, CreatePen( PS_SOLID, 1, crCur ) ) ); 
  1173.         DeleteObject( SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) ) ); 
  1174.         
  1175.  
  1176.         // Draw callout lines
  1177.         MoveToEx( hdcRender, pCallout->aptLineScaled[0].x, pCallout->aptLineScaled[0].y, NULL );
  1178.         MoveToEx( hdcAlpha, pCallout->aptLineScaled[0].x, pCallout->aptLineScaled[0].y, NULL );
  1179.         for( j=1; j < pCallout->dwNumPoints; j++ )
  1180.         {
  1181.             LineTo( hdcRender, pCallout->aptLineScaled[j].x, pCallout->aptLineScaled[j].y );
  1182.             LineTo( hdcAlpha, pCallout->aptLineScaled[j].x, pCallout->aptLineScaled[j].y );
  1183.         }
  1184.  
  1185.         // Draw arrow ends
  1186.         if( bDrawArrow )
  1187.         {
  1188.             DWORD dwEnd = pCallout->dwNumPoints-1;
  1189.  
  1190.             SetPixel( hdcRender, aptArrow[0].x, aptArrow[0].y, crCur );
  1191.             SetPixel( hdcRender, aptArrow[1].x, aptArrow[1].y, crCur );
  1192.             SetPixel( hdcRender, pCallout->aptLineScaled[ dwEnd ].x, 
  1193.                                  pCallout->aptLineScaled[ dwEnd ].y, crCur );
  1194.  
  1195.             SetPixel( hdcAlpha, aptArrow[0].x, aptArrow[0].y, RGB(255, 255, 255) );
  1196.             SetPixel( hdcAlpha, aptArrow[1].x, aptArrow[1].y, RGB(255, 255, 255) );
  1197.             SetPixel( hdcAlpha, pCallout->aptLineScaled[ dwEnd ].x, 
  1198.                                  pCallout->aptLineScaled[ dwEnd ].y, RGB(255, 255, 255) );
  1199.         }
  1200.  
  1201.         
  1202.     }
  1203.     
  1204.     // Free the pen resource
  1205.     DeleteObject( SelectObject( hdcRender, GetStockObject( WHITE_PEN ) ) );
  1206.     DeleteObject( SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) ) );
  1207.  
  1208.     // Draw callout text
  1209.     for( i=0; i < m_dwNumObjects; i++ )
  1210.     {
  1211.         COLORREF crNorm, crHigh, crCur;
  1212.         RECT     rcFill;
  1213.         
  1214.         DIDICallout *pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
  1215.         MAXSTRING    strCallout = {0};
  1216.         
  1217.         // Callout may be invisible
  1218.         if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
  1219.             continue;
  1220.  
  1221.         m_apObject[i]->GetCalloutText( strCallout, MAX_PATH-4 );
  1222.         m_apObject[i]->GetCalloutColors( &crNorm, &crHigh );
  1223.         
  1224.         
  1225.         
  1226.  
  1227.         if( IsRectEmpty( &pCallout->rcScaled ) )
  1228.             continue;
  1229.  
  1230.         // Draw callouts
  1231.         DWORD dwFormat = DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP;
  1232.  
  1233.         // Get text dimensions
  1234.         rcFill = pCallout->rcScaled;
  1235.         DrawText( hdcRender, strCallout, lstrlen( strCallout ),
  1236.                   &rcFill, dwFormat | DT_CALCRECT | DT_MODIFYSTRING );
  1237.  
  1238.       
  1239.         // Horizontal alignment
  1240.         if( pCallout->dwTextAlign == DIDAL_CENTERED )
  1241.         {
  1242.             dwFormat |= DT_CENTER;
  1243.             OffsetRect( &rcFill, (pCallout->rcScaled.right - rcFill.right) / 2, 0 );
  1244.         }
  1245.         else if( pCallout->dwTextAlign & DIDAL_RIGHTALIGNED )
  1246.         {
  1247.             dwFormat |= DT_RIGHT;
  1248.             OffsetRect( &rcFill, (pCallout->rcScaled.right - rcFill.right ), 0 );
  1249.         }
  1250.         else
  1251.         {
  1252.             dwFormat |= DT_LEFT;
  1253.         }
  1254.  
  1255.         // Vertical alignment
  1256.         if( pCallout->dwTextAlign == DIDAL_MIDDLE )
  1257.         {
  1258.             dwFormat |= DT_VCENTER;
  1259.             OffsetRect( &rcFill, 0, (pCallout->rcScaled.bottom - rcFill.bottom) / 2 );
  1260.         }
  1261.         else if( pCallout->dwTextAlign & DIDAL_BOTTOMALIGNED ) 
  1262.         {
  1263.             dwFormat |= DT_BOTTOM;
  1264.             OffsetRect( &rcFill, 0, (pCallout->rcScaled.bottom - rcFill.bottom) );
  1265.         }
  1266.         else
  1267.         {
  1268.             dwFormat |= DT_TOP;
  1269.         }
  1270.  
  1271.         // First replace the background area behind the text to cover up
  1272.         // intersecting lines
  1273.         
  1274.         // Pad the returned rect
  1275.         InflateRect( &rcFill, 5, 5 );
  1276.  
  1277.         // But make sure the rect still fits on the screen
  1278.         rcFill.left   = max( rcFill.left,   0 );
  1279.         rcFill.top    = max( rcFill.top,    0 );
  1280.         rcFill.right  = min( rcFill.right,  info.dsBm.bmWidth );
  1281.         rcFill.bottom = min( rcFill.bottom, info.dsBm.bmHeight );
  1282.  
  1283.         RestoreRect( m_ahImages[ m_dwActiveView ], &rcFill, pCleanPixels );
  1284.         if( hdcAlpha )
  1285.             FillRect( hdcAlpha, &rcFill, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
  1286.  
  1287.         // Fill behind the text
  1288.         SetTextColor( hdcRender, CRFromColor(m_BkColor) );
  1289.         for( int x = -1; x <= 1; x++ )
  1290.         {
  1291.             for( int y = -1; y <= 1; y++ )
  1292.             {
  1293.                 RECT rcText = pCallout->rcScaled;
  1294.                 OffsetRect( &rcText, x, y );
  1295.  
  1296.                 DrawText( hdcRender, strCallout, lstrlen( strCallout ),
  1297.                   &rcText, dwFormat );
  1298.  
  1299.                 DrawText( hdcAlpha, strCallout, lstrlen( strCallout ),
  1300.                   &rcText, dwFormat );
  1301.             }
  1302.         }
  1303.  
  1304.         // Now draw the actual text
  1305.         crCur = ( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() ) ? crHigh : crNorm;     
  1306.         SetTextColor( hdcRender, crCur );
  1307.  
  1308.         DrawText( hdcRender, strCallout, lstrlen( strCallout ),
  1309.                   &(pCallout->rcScaled), dwFormat );
  1310.         
  1311.         DrawText( hdcAlpha, strCallout, lstrlen( strCallout ),
  1312.                   &(pCallout->rcScaled), dwFormat );
  1313.         
  1314.  
  1315.  
  1316.         // If the TOOLTIP flag is set and the callout text doesn't fit within
  1317.         // the scaled rect, we need to draw the full text
  1318.         if( DIDICOS_TOOLTIP & m_apObject[i]->GetCalloutState() )
  1319.         {
  1320.             SIZE TextSize = {0};
  1321.             
  1322.             // This string was modified by the first call to draw text, so we
  1323.             // need to get a fresh copy
  1324.             m_apObject[i]->GetCalloutText( strCallout, MAX_PATH-4 );
  1325.             GetTextExtentPoint32( hdcRender, strCallout, lstrlen( strCallout ), &TextSize );
  1326.  
  1327.             if( TextSize.cx > ( pCallout->rcScaled.right - pCallout->rcScaled.left ) )
  1328.             {
  1329.                 // Yep, the text is too big and is marked as a tooltip candidate.
  1330.                 RECT rcBitmap = { 0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight };
  1331.                 DrawTooltip( hdcRender, hdcAlpha, strCallout, &rcBitmap, &(pCallout->rcScaled),
  1332.                              CRFromColor( m_BkColor ), crNorm, crHigh );
  1333.                 
  1334.             }
  1335.  
  1336.         }
  1337.  
  1338.     }
  1339.  
  1340.     
  1341.  
  1342.     // Finalize all rendering
  1343.     GdiFlush();
  1344.  
  1345.     // Copy the freshly rendered image to the render target
  1346.     switch( eTarget )
  1347.     {
  1348.         case DIDIRT_SURFACE:
  1349.             // Since the image is being transfered to a Direct3D surface, the stored
  1350.             // alpha information could be used.
  1351.             ApplyAlphaChannel( m_ahImages[ m_dwActiveView ], hbmpAlpha, ( (m_BkColor & ALPHA_MASK) == ALPHA_MASK ) );
  1352.             rcBitmap.right  = info.dsBm.bmWidth;
  1353.             rcBitmap.bottom = info.dsBm.bmHeight;
  1354.  
  1355.             hr = D3DXLoadSurfaceFromMemory( (LPDIRECT3DSURFACE9) pvTarget,
  1356.                                              NULL, NULL, info.dsBm.bmBits,
  1357.                                              D3DFMT_A8R8G8B8, 
  1358.                                              info.dsBm.bmWidthBytes,
  1359.                                              NULL, &rcBitmap, 
  1360.                                              D3DX_FILTER_NONE, 0 );
  1361.             break;
  1362.  
  1363.         case DIDIRT_DC:
  1364.             BitBlt( (HDC) pvTarget, 0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight,
  1365.                           hdcRender, 0, 0, SRCCOPY );
  1366.             break;
  1367.     
  1368.         default:
  1369.             // Invalid render target
  1370.             hr = DIERR_INVALIDPARAM;
  1371.             goto LCleanReturn;
  1372.     }   
  1373.  
  1374.     
  1375.  
  1376. LCleanReturn:
  1377.     
  1378.     // Restore the background
  1379.     if( pSavedPixels )
  1380.         CopyMemory( info.dsBm.bmBits, pSavedPixels, info.dsBm.bmWidthBytes * info.dsBm.bmHeight );
  1381.   
  1382.     DeleteDC( hdcRender );
  1383.     DeleteDC( hdcAlpha );
  1384.     DeleteObject( hbmpAlpha );
  1385.  
  1386.     delete [] pSavedPixels;
  1387.     delete [] pCleanPixels;
  1388.     return hr;
  1389. }
  1390.  
  1391.  
  1392.  
  1393.  
  1394.  
  1395. //-----------------------------------------------------------------------------
  1396. // Name: AddObject
  1397. // Desc: Adds an object to the current list according to object ID. If an 
  1398. //       object with the given ID already exists, a pointer to it returned. 
  1399. //       Otherwise, a new object is created and a pointer to the new object
  1400. //       is returned. Returns NULL if memory couldn't be allocated.
  1401. //-----------------------------------------------------------------------------
  1402. HRESULT CDIDevImage::AddObject( DWORD dwID )
  1403. {
  1404.     CDIDIObject* pObject = NULL;
  1405.  
  1406.     // Search through current objects
  1407.     if( GetObject( dwID ) )
  1408.         return DI_OK;
  1409.  
  1410.     // Did not find object. Create a new object, and store pointer
  1411.     pObject = new CDIDIObject( dwID, m_dwNumViews );
  1412.     if( NULL == pObject )
  1413.         return DIERR_OUTOFMEMORY;
  1414.  
  1415.     m_apObject[m_dwNumObjects++] = pObject;
  1416.     
  1417.     return DI_OK;
  1418. }
  1419.  
  1420.  
  1421.  
  1422.  
  1423. //-----------------------------------------------------------------------------
  1424. // Name: GetObject
  1425. // Desc: If an object with given ID exist, a pointer to it is returned
  1426. //-----------------------------------------------------------------------------
  1427. CDIDIObject* CDIDevImage::GetObject( DWORD dwID )
  1428. {
  1429.     for( UINT i=0; i < m_dwNumObjects; i++ )
  1430.     {
  1431.         if( m_apObject[i]->GetID() == dwID )
  1432.             return m_apObject[i];
  1433.     }
  1434.  
  1435.     return NULL;
  1436. }
  1437.  
  1438.  
  1439.  
  1440.  
  1441. //-----------------------------------------------------------------------------
  1442. // Name: LoadImageInfo
  1443. // Desc: helper function to retrieve callout / image data from
  1444. //       DirectInput
  1445. //-----------------------------------------------------------------------------
  1446. HRESULT CDIDevImage::LoadImageInfo( LPDIRECTINPUTDEVICE8 pDIDevice )
  1447. {
  1448.     HRESULT hr;
  1449.     DWORD   dwBufferCount = 0;
  1450.     DIDEVICEIMAGEINFOHEADER dihImageHeader = {0};
  1451.     DIDEVICEIMAGEINFO *pInfo = NULL;
  1452.  
  1453.     // properly initialize the structure before it can be used
  1454.     dihImageHeader.dwSize = sizeof( DIDEVICEIMAGEINFOHEADER );
  1455.     dihImageHeader.dwSizeImageInfo = sizeof( DIDEVICEIMAGEINFO );
  1456.     
  1457.     // since m_dihImageHeader.dwBufferSize is 0, this call serves to determine
  1458.     // the minimum buffer size required to hold information for all the images
  1459.     hr = pDIDevice->GetImageInfo( &dihImageHeader );
  1460.     if( FAILED(hr) )
  1461.         return hr;
  1462.  
  1463.     // at this point, m_lpDidImgHeader->dwBufferUsed has been set by
  1464.     // the GetImageInfo method to minimum buffer size needed, so allocate.
  1465.     dihImageHeader.dwBufferSize = dihImageHeader.dwBufferUsed;
  1466.     dihImageHeader.lprgImageInfoArray = (DIDEVICEIMAGEINFO*) new BYTE[dihImageHeader.dwBufferSize];
  1467.  
  1468.     // make sure memory has been allocated
  1469.     if( NULL == dihImageHeader.lprgImageInfoArray )
  1470.         return DIERR_OUTOFMEMORY;
  1471.  
  1472.     // now that the dwBufferSize has been filled, and lprgImageArray allocated,
  1473.     // we call GetImageInfo again to get the image data
  1474.     hr = pDIDevice->GetImageInfo( &dihImageHeader );
  1475.     if( FAILED(hr) )
  1476.         goto LCleanReturn;
  1477.     
  1478.     // Allocate space for all the object/callouts/overlays
  1479.     m_apObject = new CDIDIObject* [dihImageHeader.dwcButtons + 
  1480.                                    dihImageHeader.dwcAxes +
  1481.                                    dihImageHeader.dwcPOVs];
  1482.  
  1483.     if( NULL == m_apObject )
  1484.     {
  1485.         hr = DIERR_OUTOFMEMORY;
  1486.         goto LCleanReturn;
  1487.     }
  1488.  
  1489.     m_dwNumViews = dihImageHeader.dwcViews;
  1490.  
  1491.     // Allocate space for background images
  1492.     m_atszImagePath = new TCHAR[m_dwNumViews][MAX_PATH];
  1493.     if( NULL == m_atszImagePath )
  1494.     {
  1495.         hr = DIERR_OUTOFMEMORY;
  1496.         goto LCleanReturn;
  1497.     }
  1498.  
  1499.     ZeroMemory( m_atszImagePath, sizeof(m_atszImagePath) );
  1500.  
  1501.     m_ahImages = new HBITMAP[m_dwNumViews];
  1502.     if( NULL == m_ahImages )
  1503.     {
  1504.         hr = DIERR_OUTOFMEMORY;
  1505.         goto LCleanReturn;
  1506.     }
  1507.  
  1508.     ZeroMemory( m_ahImages, sizeof(m_ahImages) );
  1509.  
  1510.     // Fill the data from the ImageHeader
  1511.     pInfo = dihImageHeader.lprgImageInfoArray;
  1512.     dwBufferCount = dihImageHeader.dwBufferUsed;
  1513.  
  1514.     while( dwBufferCount > 0)
  1515.     {
  1516.         if( pInfo->dwViewID > m_dwNumViews )
  1517.         {
  1518.             // Error in the input format, this is out of bounds for our array
  1519.             hr = E_FAIL;
  1520.             goto LCleanReturn;
  1521.         }
  1522.  
  1523.         if( pInfo->dwFlags & DIDIFT_CONFIGURATION )
  1524.         {
  1525.             lstrcpy( m_atszImagePath[pInfo->dwViewID], pInfo->tszImagePath );
  1526.         }
  1527.         else if( pInfo->dwFlags & DIDIFT_OVERLAY )
  1528.         {
  1529.             hr = AddObject( pInfo->dwObjID );
  1530.             if( FAILED(hr) )
  1531.                 goto LCleanReturn;
  1532.  
  1533.             CDIDIObject *pDIObj = GetObject( pInfo->dwObjID ); 
  1534.             if( NULL == pDIObj )
  1535.             {
  1536.                 hr = DIERR_OUTOFMEMORY;
  1537.                 goto LCleanReturn;
  1538.             }
  1539.  
  1540.             // Overlay
  1541.             if( pInfo->tszImagePath[0] )
  1542.                 pDIObj->SetOverlay( pInfo->dwViewID, pInfo->tszImagePath, pInfo->rcOverlay );
  1543.            
  1544.  
  1545.             // Callout
  1546.             pDIObj->SetCallout( pInfo->dwViewID, pInfo->dwcValidPts, pInfo->rgptCalloutLine, pInfo->rcCalloutRect, pInfo->dwTextAlign );
  1547.         }
  1548.         
  1549.         pInfo++;
  1550.         dwBufferCount -= dihImageHeader.dwSizeImageInfo;
  1551.     }
  1552.  
  1553.     // We made it this far, set the return value as success.
  1554.     hr = DI_OK;
  1555.  
  1556. LCleanReturn:
  1557.     
  1558.     // Release the resources used for the image info structure
  1559.     delete [] dihImageHeader.lprgImageInfoArray;
  1560.     return hr;
  1561. }
  1562.  
  1563.  
  1564.  
  1565.  
  1566. //-----------------------------------------------------------------------------
  1567. // Name: CreateCustomImageInfo
  1568. // Desc: Create a default UI for the given device, and fill in all neccesary
  1569. //       structures to support rendering
  1570. //-----------------------------------------------------------------------------
  1571. HRESULT CDIDevImage::CreateCustomImageInfo( LPDIRECTINPUTDEVICE8 pDIDevice )
  1572. {
  1573.     HRESULT hr;
  1574.     DIDEVCAPS didc;
  1575.  
  1576.     // Allocate space for all the device's objects (axes, buttons, POVS)
  1577.     ZeroMemory( &didc, sizeof(DIDEVCAPS) );
  1578.     didc.dwSize = sizeof(DIDEVCAPS);
  1579.     hr = pDIDevice->GetCapabilities( &didc );
  1580.     if( FAILED(hr) )
  1581.         return hr;
  1582.  
  1583.     m_apObject = new CDIDIObject* [didc.dwAxes + didc.dwButtons + didc.dwPOVs];
  1584.     if( NULL == m_apObject )
  1585.         return DIERR_OUTOFMEMORY;
  1586.  
  1587.     
  1588.     hr = pDIDevice->EnumObjects( EnumDeviceObjectsCB, this, DIDFT_AXIS );
  1589.     if( FAILED(hr) )
  1590.         return hr;
  1591.  
  1592.     hr = pDIDevice->EnumObjects( EnumDeviceObjectsCB, this, DIDFT_BUTTON );
  1593.     if( FAILED(hr))
  1594.         return hr;
  1595.  
  1596.     hr = pDIDevice->EnumObjects( EnumDeviceObjectsCB, this, DIDFT_POV );
  1597.     if( FAILED(hr))
  1598.         return hr;
  1599.  
  1600.     return DI_OK;
  1601. }
  1602.  
  1603.  
  1604.  
  1605.  
  1606. //-----------------------------------------------------------------------------
  1607. // Name: LoadImages
  1608. // Desc: Load all images associated with the active view
  1609. //-----------------------------------------------------------------------------
  1610. HRESULT CDIDevImage::LoadImages()
  1611. {
  1612.     UINT               i;
  1613.     HRESULT            hr;
  1614.     SIZE               sizeInit = {0};
  1615.     SIZE               sizeScaled = {0};
  1616.     FLOAT              fxScale, fyScale;
  1617.     D3DXIMAGE_INFO     d3dxImageInfo;
  1618.     LPDIRECT3DSURFACE9 pLoadSurface = NULL;
  1619.     LPDIRECT3DSURFACE9 pScaleSurface = NULL;
  1620.     
  1621.  
  1622.     // Create a temporary surface
  1623.     pLoadSurface = GetCloneSurface( DIDICONST_MAX_IMAGE_WIDTH, DIDICONST_MAX_IMAGE_HEIGHT );
  1624.     
  1625.     // Load the background image onto the temporary loading surface
  1626.     hr = D3DXLoadSurfaceFromFile( pLoadSurface, NULL, NULL, 
  1627.                                   m_atszImagePath[m_dwActiveView],
  1628.                                   NULL, D3DX_FILTER_NONE, 
  1629.                                   NULL, &d3dxImageInfo );
  1630.  
  1631.     if( FAILED(hr) )
  1632.         goto LCleanReturn;
  1633.  
  1634.    
  1635.     // The actual dimensions of the render surface are determined
  1636.     // by the background image, the overlay images, and the 
  1637.     // callout rects. 
  1638.     sizeInit.cx = d3dxImageInfo.Width;
  1639.     sizeInit.cy = d3dxImageInfo.Height;
  1640.  
  1641.     for( i=0; i < m_dwNumObjects; i++ )
  1642.     {
  1643.         DIDICallout* pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
  1644.         
  1645.         sizeInit.cx = max( sizeInit.cx, pCallout->rcInit.right );
  1646.         sizeInit.cy = max( sizeInit.cy, pCallout->rcInit.bottom );
  1647.     }
  1648.  
  1649.     // Determine the scaling parameters
  1650.     switch( m_dwScaleMethod )
  1651.     {
  1652.         case( DIDISOIS_RESIZE ) :
  1653.             sizeScaled.cx = m_dwWidthPref;
  1654.             sizeScaled.cy = m_dwHeightPref;
  1655.             break;
  1656.  
  1657.         case( DIDISOIS_MAINTAINASPECTUSINGWIDTH ) :
  1658.             sizeScaled.cx = m_dwWidthPref;
  1659.             sizeScaled.cy = (LONG) ( 0.5 + sizeInit.cy * ( (FLOAT)m_dwWidthPref  / sizeInit.cx ) );
  1660.             break;
  1661.   
  1662.         case( DIDISOIS_MAINTAINASPECTUSINGHEIGHT ) :
  1663.             sizeScaled.cx = (LONG) ( 0.5 + sizeInit.cx * ( (FLOAT)m_dwHeightPref / sizeInit.cy ) );
  1664.             sizeScaled.cy = m_dwHeightPref;
  1665.             break;
  1666.  
  1667.         case( DIDISOIS_DEFAULT ) :
  1668.         default :
  1669.             sizeScaled.cx = sizeInit.cx;
  1670.             sizeScaled.cy = sizeInit.cy;
  1671.             break;  
  1672.     }
  1673.  
  1674.     // Calculate scaling multipliers
  1675.     fxScale = (FLOAT)sizeScaled.cx / sizeInit.cx;
  1676.     fyScale = (FLOAT)sizeScaled.cy / sizeInit.cy;
  1677.  
  1678.     // Scale all object display parameters
  1679.     for( i=0; i < m_dwNumObjects; i++ )
  1680.     {
  1681.         m_apObject[i]->ScaleView( m_dwActiveView, fxScale, fyScale );
  1682.     }
  1683.  
  1684.     // Load the background image
  1685.     hr = CreateScaledSurfaceCopy( pLoadSurface, d3dxImageInfo.Width, d3dxImageInfo.Height, 
  1686.                                   fxScale, fyScale, &pScaleSurface );
  1687.     if( FAILED(hr) )
  1688.         goto LCleanReturn;
  1689.  
  1690.  
  1691.     // Create a DIB section for the loaded image
  1692.     hr = CreateDIBSectionFromSurface( pScaleSurface, &(m_ahImages[ m_dwActiveView ]), &sizeScaled );
  1693.     if( FAILED(hr) )
  1694.         goto LCleanReturn;
  1695.  
  1696.     SAFE_RELEASE( pScaleSurface );
  1697.  
  1698.     // Apply the background color
  1699.     FillBackground( m_ahImages[ m_dwActiveView ], m_BkColor );
  1700.  
  1701.     // Load all object images
  1702.     for( i=0; i < m_dwNumObjects; i++ )
  1703.     {
  1704.         DIDIOverlay *pOverlay = m_apObject[i]->GetOverlay( m_dwActiveView );
  1705.  
  1706.         // Load the file onto the temporary surface
  1707.         if( !pOverlay->strImagePath[0] )
  1708.             continue;
  1709.  
  1710.         hr = D3DXLoadSurfaceFromFile( pLoadSurface, 
  1711.                                       NULL, NULL, 
  1712.                                       pOverlay->strImagePath,
  1713.                                       NULL, D3DX_FILTER_NONE, 
  1714.                                       NULL, &d3dxImageInfo );
  1715.         if( FAILED(hr) )
  1716.             continue;
  1717.         
  1718.         // Since overlay rectanges are actually defined by the image size, some
  1719.         // of the image info files simply define the top-left coordinate of the
  1720.         // rectangle. We may want good data for the overlay rectangle, so set
  1721.         // the rect based on image size
  1722.         pOverlay->rcInit.bottom = pOverlay->rcInit.top  + d3dxImageInfo.Height;
  1723.         pOverlay->rcInit.right  = pOverlay->rcInit.left + d3dxImageInfo.Width;
  1724.         ScaleRect( &( pOverlay->rcInit), &( pOverlay->rcScaled ), fxScale, fyScale );
  1725.  
  1726.         // Scale the overlay
  1727.         hr = CreateScaledSurfaceCopy( pLoadSurface, d3dxImageInfo.Width, d3dxImageInfo.Height,
  1728.                                       fxScale, fyScale, &pScaleSurface );
  1729.         if( FAILED(hr) )
  1730.             goto LCleanReturn;
  1731.      
  1732.         // Load the stored bitmap from the scaled D3D surface
  1733.         hr = CreateDIBSectionFromSurface( pScaleSurface, &(pOverlay->hImage) );
  1734.         if( FAILED(hr) )
  1735.             goto LCleanReturn;
  1736.  
  1737.         SAFE_RELEASE( pScaleSurface );
  1738.     }
  1739.  
  1740.     hr = DI_OK;
  1741.  
  1742. LCleanReturn:
  1743.  
  1744.     SAFE_RELEASE( pLoadSurface );
  1745.     SAFE_RELEASE( pScaleSurface );
  1746.     
  1747.     return hr;
  1748. }
  1749.  
  1750.  
  1751.  
  1752.  
  1753. //-----------------------------------------------------------------------------
  1754. // Name: GetCustomUISize
  1755. // Desc: Determine the dimensions of the custom UI based on default values and
  1756. //       user-supplied sizing information.
  1757. //-----------------------------------------------------------------------------
  1758. HRESULT CDIDevImage::GetCustomUISize( SIZE* pSize )
  1759. {
  1760.     if( pSize == NULL )
  1761.         return DIERR_INVALIDPARAM;
  1762.  
  1763.     // Calculate view dimensions based on values set during a call to 
  1764.     // SetOutputImageSize(), or the default values defined in the header
  1765.  
  1766.     switch( m_dwScaleMethod )
  1767.     {
  1768.     case DIDISOIS_RESIZE :
  1769.         pSize->cx = m_dwWidthPref;
  1770.         pSize->cy = m_dwHeightPref;
  1771.         break;
  1772.  
  1773.     case DIDISOIS_MAINTAINASPECTUSINGWIDTH :
  1774.         pSize->cx = m_dwWidthPref;
  1775.         pSize->cy = (LONG) ( 0.5 + DIDICONST_CUSTOM_VIEW_HEIGHT *
  1776.                                ( (FLOAT)m_dwWidthPref / DIDICONST_CUSTOM_VIEW_WIDTH ) );
  1777.         break;
  1778.  
  1779.     case DIDISOIS_MAINTAINASPECTUSINGHEIGHT :
  1780.         pSize->cy = m_dwHeightPref;
  1781.         pSize->cx = (LONG) ( 0.5 + DIDICONST_CUSTOM_VIEW_WIDTH *
  1782.                                ( (FLOAT)m_dwHeightPref / DIDICONST_CUSTOM_VIEW_HEIGHT ) );
  1783.         break;
  1784.  
  1785.     default:
  1786.         pSize->cx = DIDICONST_CUSTOM_VIEW_WIDTH;
  1787.         pSize->cy = DIDICONST_CUSTOM_VIEW_HEIGHT;
  1788.     };
  1789.  
  1790.     return DI_OK;
  1791. }
  1792.  
  1793.  
  1794.  
  1795.  
  1796. //-----------------------------------------------------------------------------
  1797. // Name: BuildCustomUI
  1798. // Desc: Creates the callout rects for each view based on stored sizing 
  1799. // information and callout strings.
  1800. //-----------------------------------------------------------------------------
  1801. HRESULT CDIDevImage::BuildCustomUI()
  1802. {
  1803.     HDC     hdc      = NULL;
  1804.     SIZE    size     = {0};
  1805.     UINT    i        = 0;
  1806.  
  1807.     int nMaxNameWidth     = 0;
  1808.     int nMaxNameHeight    = 0;
  1809.     int nMaxCalloutWidth  = 0;
  1810.     int nMaxCalloutHeight = 0;
  1811.     int nRowsPerView      = 0;
  1812.     int nColsPerView      = 0;
  1813.     int nNumVisObjects    = 0;
  1814.  
  1815.     const int GUTTER_SIZE    = 20;
  1816.     const int PADDING_SIZE   = 20;
  1817.     const int SPACING_WIDTH  = 10;
  1818.     const int SPACING_HEIGHT = 10;
  1819.  
  1820.     const int MAX_CHARS_OBJECT = 20;
  1821.     const int MAX_CHARS_ACTION = 20;
  1822.  
  1823.     // we need a device context in order to evaluate the text metrics
  1824.     hdc = CreateDC( TEXT("DISPLAY"), NULL, NULL, NULL );
  1825.     if( NULL == hdc )
  1826.         return E_FAIL;
  1827.  
  1828.     // select the font into the dc
  1829.     SelectObject( hdc, m_hFont );
  1830.  
  1831.     // determine the largest device name
  1832.     for( i=0; i < m_dwNumObjects; i++ )
  1833.     {
  1834.         if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
  1835.             continue;
  1836.  
  1837.         nNumVisObjects++;
  1838.  
  1839.         TCHAR str[ MAX_PATH ] = {0};
  1840.        
  1841.         m_apObject[i]->GetName( str, MAX_PATH );
  1842.         if( lstrlen(str) > 15 )
  1843.             lstrcpy( &str[15], TEXT("...") );
  1844.         if( str && GetTextExtentPoint32( hdc, str, lstrlen( str ), &size ) )
  1845.         {
  1846.             nMaxNameWidth  = max( nMaxNameWidth,  size.cx );
  1847.             nMaxNameHeight = max( nMaxNameHeight, size.cy ); 
  1848.         }
  1849.  
  1850.         m_apObject[i]->GetCalloutText( str, MAX_PATH );
  1851.         if( lstrlen(str) > 15 )
  1852.             lstrcpy( &str[15], TEXT("...") );
  1853.         if( str && GetTextExtentPoint32( hdc, str, lstrlen( str ), &size ) )
  1854.         {
  1855.             nMaxCalloutWidth  = max( nMaxCalloutWidth,  size.cx );
  1856.             nMaxCalloutHeight = max( nMaxCalloutHeight, size.cy ); 
  1857.         }
  1858.        
  1859.     }
  1860.     
  1861.     // Optionally, you can help constrain the callout sizes by restricting the
  1862.     // string lengths.
  1863.     TEXTMETRIC tm = {0};
  1864.     if( GetTextMetrics( hdc, &tm ) )
  1865.     {
  1866.         nMaxCalloutWidth = min( nMaxCalloutWidth, MAX_CHARS_ACTION * tm.tmAveCharWidth );
  1867.         nMaxNameWidth    = min( nMaxNameWidth,    MAX_CHARS_OBJECT * tm.tmAveCharWidth );
  1868.     }
  1869.  
  1870.     // Release resources
  1871.     DeleteDC( hdc );
  1872.  
  1873.     // Calculate view dimensions
  1874.     GetCustomUISize( &size );
  1875.  
  1876.     // determine how many callouts we can fit on a single view
  1877.     nColsPerView = ( size.cx - (2 * PADDING_SIZE) + GUTTER_SIZE ) / 
  1878.                    ( nMaxNameWidth + nMaxCalloutWidth + SPACING_WIDTH + GUTTER_SIZE );
  1879.  
  1880.     nColsPerView = max( nColsPerView, 1 );
  1881.  
  1882.     nRowsPerView = ( size.cy - (2 * PADDING_SIZE) ) /
  1883.                    ( nMaxNameHeight + SPACING_HEIGHT );
  1884.  
  1885.     nRowsPerView = max( nRowsPerView, 1 );
  1886.  
  1887.     m_dwNumViews = nNumVisObjects / ( nColsPerView * nRowsPerView );
  1888.     m_dwNumViews = max( m_dwNumViews, 1 );
  1889.  
  1890.     // now all the dimensions are calculated and the callouts can be
  1891.     // allocated. 
  1892.     for( i=0; i < m_dwNumObjects; i++ )
  1893.     {
  1894.         m_apObject[i]->AllocateViews( m_dwNumViews );
  1895.     }
  1896.  
  1897.     DIDICallout* pCallout = NULL;
  1898.     DIDIOverlay* pOverlay = NULL;
  1899.  
  1900.     int x = 0, y = 0;
  1901.     UINT index = 0;
  1902.  
  1903.     // Build the view by enumerating through the callouts and 
  1904.  
  1905.     // For each view...
  1906.     for( UINT view=0; view < m_dwNumViews; view++ )
  1907.     {
  1908.         x = PADDING_SIZE;
  1909.  
  1910.         // For each column...
  1911.         for( int col=0; col < nColsPerView; col++ )
  1912.         {
  1913.             y = PADDING_SIZE;
  1914.  
  1915.             // For each row...
  1916.             for( int row=0; row < nRowsPerView; row++ )
  1917.             {          
  1918.                 // Eat indices to invisible objects until an object is found or
  1919.                 // we run out.
  1920.                 while( index < m_dwNumObjects && 
  1921.                        ( DIDICOS_INVISIBLE & m_apObject[index]->GetCalloutState() ) )
  1922.                 {
  1923.                     index++;
  1924.                 }
  1925.  
  1926.                 // If we're on a valid object, calculate the screen coords
  1927.                 if( index < m_dwNumObjects )
  1928.                 {
  1929.                     pOverlay = m_apObject[index]->GetOverlay( view );
  1930.                     pCallout = m_apObject[index]->GetCallout( view );
  1931.  
  1932.                     pOverlay->rcScaled.left = x;
  1933.                     pOverlay->rcScaled.top  = y;
  1934.                     pOverlay->rcScaled.right = x + nMaxNameWidth;
  1935.                     pOverlay->rcScaled.bottom = y + nMaxNameHeight;
  1936.  
  1937.                     pCallout->rcScaled.left = x + nMaxNameWidth + SPACING_WIDTH;
  1938.                     pCallout->rcScaled.top = y;
  1939.                     pCallout->rcScaled.right = pCallout->rcScaled.left + nMaxCalloutWidth;
  1940.                     pCallout->rcScaled.bottom = y + nMaxNameHeight;
  1941.                     pCallout->dwTextAlign = DIDAL_LEFTALIGNED | DIDAL_BOTTOMALIGNED;
  1942.                 }
  1943.                 index++;
  1944.              
  1945.                 y += nMaxNameHeight + SPACING_HEIGHT;
  1946.             }
  1947.  
  1948.             x += nMaxNameWidth + nMaxCalloutWidth + SPACING_WIDTH + GUTTER_SIZE;
  1949.         }
  1950.     }
  1951.  
  1952.     // Clear the invalid flag
  1953.     m_bInvalidUI = FALSE;  
  1954.     return DI_OK;
  1955. }
  1956.  
  1957.  
  1958.  
  1959.  
  1960. //-----------------------------------------------------------------------------
  1961. // Name: CreateScaledSurfaceCopy
  1962. // Desc: Creates a new surface and copies the contents from the provided
  1963. //       source surface onto the newly created destination surface.
  1964. //-----------------------------------------------------------------------------
  1965. HRESULT CDIDevImage::CreateScaledSurfaceCopy( LPDIRECT3DSURFACE9 pSurfaceSrc,
  1966.                                               DWORD dwWidthSrc, DWORD dwHeightSrc, 
  1967.                                               FLOAT fxScale, FLOAT fyScale, 
  1968.                                               LPDIRECT3DSURFACE9 *ppSurfaceDest )
  1969. {
  1970.     HRESULT hr;
  1971.     RECT    rcSrc = {0}, rcDest = {0}; 
  1972.  
  1973.     // Verify parameters
  1974.     if( NULL == pSurfaceSrc || NULL == ppSurfaceDest )
  1975.         return DIERR_INVALIDPARAM;
  1976.  
  1977.     // Calculate creation arguments
  1978.     rcSrc.right  = dwWidthSrc-1; 
  1979.     rcSrc.bottom = dwHeightSrc-1;
  1980.     ScaleRect( &rcSrc, &rcDest, fxScale, fyScale );
  1981.     
  1982.     // Create the stored surface
  1983.     *ppSurfaceDest = GetCloneSurface( rcDest.right, rcDest.bottom );
  1984.                   
  1985.     // Since we're using a surface workaround, the d3d functions should only
  1986.     // be called if we're actually scaling the surface.
  1987.     if( EqualRect( &rcSrc, &rcDest ) )
  1988.     {
  1989.         D3DLOCKED_RECT d3drcSrc = {0};
  1990.         D3DLOCKED_RECT d3drcDest = {0};
  1991.  
  1992.         pSurfaceSrc->LockRect( &d3drcSrc, NULL, 0 );
  1993.         (*ppSurfaceDest)->LockRect( &d3drcDest, NULL, 0 );
  1994.  
  1995.         BYTE* pBitsSrc = (BYTE*) d3drcSrc.pBits;
  1996.         BYTE* pBitsDest = (BYTE*) d3drcDest.pBits;
  1997.  
  1998.         for( int y = rcDest.top; y < rcDest.bottom; y++ )
  1999.         {
  2000.             CopyMemory( pBitsDest, pBitsSrc, d3drcDest.Pitch );
  2001.             pBitsDest += d3drcDest.Pitch;
  2002.             pBitsSrc += d3drcSrc.Pitch;
  2003.         }
  2004.     }
  2005.     else
  2006.     {
  2007.         // Copy the image onto the stored surface
  2008.         hr = D3DXLoadSurfaceFromSurface( *ppSurfaceDest, 
  2009.                                           NULL, &rcDest, 
  2010.                                           pSurfaceSrc, NULL,
  2011.                                           &rcSrc, D3DX_FILTER_TRIANGLE,
  2012.                                           NULL );
  2013.  
  2014.         if( FAILED(hr) )
  2015.             goto LCleanReturn;
  2016.  
  2017.     }
  2018.  
  2019.     // Everything went OK. Return before cleaning up the new surface.
  2020.     return DI_OK;
  2021.  
  2022. LCleanReturn:
  2023.     // An error occured. Clean up the new surface before returning.
  2024.     if( *ppSurfaceDest )
  2025.     {
  2026.        (*ppSurfaceDest)->Release();
  2027.         *ppSurfaceDest = NULL;
  2028.     }
  2029.     
  2030.     return hr;
  2031. }
  2032.  
  2033.  
  2034.  
  2035.  
  2036. //-----------------------------------------------------------------------------
  2037. // Name: CleanUp
  2038. // Desc: Release all allocated memory, zero out member variables
  2039. //-----------------------------------------------------------------------------
  2040. void CDIDevImage::CleanUp()
  2041. {
  2042.     UINT i=0; //loop var
  2043.  
  2044.     // Release resources first
  2045.     DestroyImages();
  2046.  
  2047.     // Call destructors on all stored objects
  2048.     for( i=0; i < m_dwNumObjects; i++ )
  2049.     {
  2050.         delete m_apObject[i];
  2051.     }
  2052.  
  2053.     // Delete object array
  2054.     if( m_apObject )
  2055.         delete [] m_apObject;
  2056.  
  2057.  
  2058.     // Delete BITMAP storage array
  2059.     delete [] m_atszImagePath;
  2060.     delete [] m_ahImages;
  2061.  
  2062.     if( m_hFont )
  2063.         DeleteObject( m_hFont );
  2064.  
  2065.     m_apObject      = NULL;
  2066.     m_atszImagePath = NULL;
  2067.     m_ahImages      = NULL;
  2068.     m_dwNumObjects  = 0;
  2069.     m_dwNumViews    = 0;
  2070.     m_dwWidthPref   = 0;
  2071.     m_dwHeightPref  = 0;
  2072.     m_dwScaleMethod = 0;
  2073.     m_hFont         = NULL;
  2074.     m_bInitialized  = FALSE;
  2075.     m_bCustomUI     = FALSE;
  2076.     m_bInvalidUI    = TRUE;
  2077. }
  2078.  
  2079.  
  2080.  
  2081.  
  2082. //-----------------------------------------------------------------------------
  2083. // Name: DestroyImages
  2084. // Desc: Release all stored images
  2085. //-----------------------------------------------------------------------------
  2086. VOID CDIDevImage::DestroyImages()
  2087. {
  2088.     UINT i=0; //loop var
  2089.  
  2090.     // Release all background images
  2091.     if( m_ahImages )
  2092.     {
  2093.         for( i=0; i < m_dwNumViews; i++ )
  2094.         {
  2095.             if( m_ahImages[i] )
  2096.                 DeleteObject( m_ahImages[i] );
  2097.  
  2098.             m_ahImages[i] = NULL;
  2099.         }
  2100.     }
  2101.  
  2102.     // Release all object images
  2103.     for( i=0; i < m_dwNumObjects; i++ )
  2104.     {
  2105.         if( m_apObject[i] )
  2106.             m_apObject[i]->DestroyImages();
  2107.     }
  2108. };
  2109.  
  2110.  
  2111.  
  2112.  
  2113. //-----------------------------------------------------------------------------
  2114. // Name: CreateFont
  2115. // Desc: Create the GDI font to use for callout text
  2116. //-----------------------------------------------------------------------------
  2117. VOID CDIDevImage::CreateFont()
  2118. {
  2119.     // Create display font
  2120.     LOGFONT lf;
  2121.     ZeroMemory( &lf, sizeof(LOGFONT) );
  2122.     lf.lfHeight = 14;
  2123.     lf.lfWeight = 700;
  2124.     lf.lfCharSet = DEFAULT_CHARSET;
  2125.     lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  2126.     _tcscpy( lf.lfFaceName, TEXT("arial") );
  2127.  
  2128.     m_hFont = CreateFontIndirect( &lf );
  2129.  
  2130.     // Have a backup plan
  2131.     if( NULL == m_hFont )
  2132.         m_hFont = (HFONT) GetStockObject( DEFAULT_GUI_FONT );
  2133. }
  2134.  
  2135.  
  2136.  
  2137.  
  2138. //-----------------------------------------------------------------------------
  2139. // Name: CDIDIObject
  2140. // Desc: Constructor
  2141. //-----------------------------------------------------------------------------
  2142. CDIDIObject::CDIDIObject( DWORD dwID, DWORD dwNumViews )
  2143. {
  2144.     m_dwID        = dwID; 
  2145.     m_crNormColor = RGB(150, 150, 200);
  2146.     m_crHighColor = RGB(255, 255, 255);
  2147.     m_dwNumViews  = dwNumViews;
  2148.  
  2149.  
  2150.     m_aCallout = NULL;
  2151.     m_aOverlay = NULL;
  2152.     m_dwState  = 0;
  2153.  
  2154.     AllocateViews( dwNumViews );
  2155.  
  2156.     lstrcpy( m_strCallout, TEXT("_ _ _") );
  2157.     lstrcpy( m_strName,    TEXT("") );
  2158. };
  2159.  
  2160.  
  2161.  
  2162.  
  2163. //-----------------------------------------------------------------------------
  2164. // Name: ~CDIDIObject
  2165. // Desc: Destructor
  2166. //-----------------------------------------------------------------------------
  2167. CDIDIObject::~CDIDIObject() 
  2168. {
  2169.     DestroyImages();
  2170.     delete [] m_aCallout;
  2171.     delete [] m_aOverlay;
  2172. };
  2173.  
  2174.  
  2175.  
  2176.  
  2177. //-----------------------------------------------------------------------------
  2178. // Name: AllocateViews
  2179. // Desc: The number of views for a custom UI can change, requiring the need
  2180. //       to free and reallocate resources depending on the number of views.
  2181. //-----------------------------------------------------------------------------
  2182. HRESULT CDIDIObject::AllocateViews( DWORD dwNumViews ) 
  2183. {
  2184.     // Release current views
  2185.     delete [] m_aCallout;
  2186.     delete [] m_aOverlay;
  2187.  
  2188.     m_dwNumViews = 0;
  2189.  
  2190.     m_aCallout = new DIDICallout[dwNumViews];
  2191.     if( NULL == m_aCallout )
  2192.         return DIERR_OUTOFMEMORY;
  2193.  
  2194.     m_aOverlay = new DIDIOverlay[dwNumViews];
  2195.     if( NULL == m_aOverlay )
  2196.     {
  2197.         delete[] m_aCallout;
  2198.         m_aCallout = NULL;
  2199.         return DIERR_OUTOFMEMORY;
  2200.     }
  2201.  
  2202.     ZeroMemory( m_aCallout, sizeof(DIDICallout) * dwNumViews );
  2203.     ZeroMemory( m_aOverlay, sizeof(DIDIOverlay) * dwNumViews );
  2204.  
  2205.     m_dwNumViews = dwNumViews;
  2206.     return DI_OK;
  2207. };
  2208.  
  2209.  
  2210.  
  2211.  
  2212. //-----------------------------------------------------------------------------
  2213. // Name: SetOverlay
  2214. // Desc: Sets the values for an overlay in the object's current list
  2215. //-----------------------------------------------------------------------------
  2216. VOID CDIDIObject::SetOverlay( DWORD dwViewID, LPCTSTR strImagePath, RECT rect )
  2217. {
  2218.     m_aOverlay[dwViewID].rcInit = rect;
  2219.     m_aOverlay[dwViewID].rcScaled = rect;
  2220.     _tcsncpy( m_aOverlay[dwViewID].strImagePath, strImagePath, MAX_PATH );
  2221.     m_aOverlay[dwViewID].strImagePath[MAX_PATH-1] = _T('\0');
  2222. }
  2223.  
  2224.  
  2225.  
  2226.  
  2227. //-----------------------------------------------------------------------------
  2228. // Name: SetCallout
  2229. // Desc: Adds the values for a callout in the object's current list
  2230. //-----------------------------------------------------------------------------
  2231. VOID CDIDIObject::SetCallout( DWORD dwViewID, DWORD dwNumPoints, POINT *aptLine, RECT rect, DWORD dwTextAlign )
  2232. {
  2233.     m_aCallout[dwViewID].dwNumPoints = dwNumPoints;
  2234.     m_aCallout[dwViewID].rcInit = rect;
  2235.     m_aCallout[dwViewID].rcScaled = rect;
  2236.     m_aCallout[dwViewID].dwTextAlign = dwTextAlign;
  2237.  
  2238.     for( int i=0; i < 5; i++)
  2239.     {
  2240.         m_aCallout[dwViewID].aptLineInit[i] = aptLine[i];
  2241.         m_aCallout[dwViewID].aptLineScaled[i] = aptLine[i];
  2242.     }
  2243. }
  2244.  
  2245.  
  2246.  
  2247.  
  2248. //-----------------------------------------------------------------------------
  2249. // Name: DestroyImages
  2250. // Desc: Release all stored images
  2251. //-----------------------------------------------------------------------------
  2252. VOID CDIDIObject::DestroyImages()
  2253. {
  2254.     UINT i=0; //loop var
  2255.  
  2256.     // Release all object images
  2257.     for( i=0; i < m_dwNumViews; i++ )
  2258.     {
  2259.         if( m_aOverlay[i].hImage )
  2260.             DeleteObject( m_aOverlay[i].hImage );
  2261.  
  2262.         m_aOverlay[i].hImage = NULL;
  2263.     }
  2264. };
  2265.  
  2266.  
  2267.  
  2268.  
  2269. //-----------------------------------------------------------------------------
  2270. // Name: SetCalloutText
  2271. // Desc: copy as many characters as will fit, leaving room for the terminating
  2272. //       null and 3 elipses.
  2273. //-----------------------------------------------------------------------------
  2274. VOID CDIDIObject::SetCalloutText( LPCTSTR strText )
  2275. {
  2276.     _tcsncpy( m_strCallout, strText, MAX_PATH - 4 );
  2277. }
  2278.  
  2279.  
  2280.  
  2281.  
  2282. //-----------------------------------------------------------------------------
  2283. // Name: GetCalloutText
  2284. // Desc: Retrieve the current callout text from the name buffer up to the 
  2285. //       amount of characters specified by dwSize
  2286. //-----------------------------------------------------------------------------
  2287. VOID CDIDIObject::GetCalloutText( LPTSTR strText, DWORD dwSize )
  2288. {
  2289.     _tcsncpy( strText, m_strCallout, dwSize );
  2290. }
  2291.  
  2292.  
  2293.  
  2294.  
  2295. //-----------------------------------------------------------------------------
  2296. // Name: ScaleView
  2297. // Desc: Scale all rects and points to the given scaling factors
  2298. //-----------------------------------------------------------------------------
  2299. VOID CDIDIObject::ScaleView( DWORD dwViewID, FLOAT fxScale, FLOAT fyScale )
  2300. {
  2301.     UINT i=0;
  2302.  
  2303.     // Overlay/Callout Rects
  2304.     ScaleRect( &(m_aOverlay[dwViewID].rcInit), 
  2305.                &(m_aOverlay[dwViewID].rcScaled),
  2306.                fxScale, fyScale );
  2307.  
  2308.     ScaleRect( &(m_aCallout[dwViewID].rcInit), 
  2309.                &(m_aCallout[dwViewID].rcScaled),
  2310.                fxScale, fyScale );
  2311.  
  2312.     // Callout Lines
  2313.     for( i=0; i < 5; i++ )
  2314.     {
  2315.         ScalePoint( &(m_aCallout[dwViewID].aptLineInit[i]), 
  2316.                     &(m_aCallout[dwViewID].aptLineScaled[i]),
  2317.                     fxScale, fyScale );
  2318.     }
  2319.  
  2320. }
  2321.  
  2322.  
  2323.  
  2324.  
  2325. //-----------------------------------------------------------------------------
  2326. // Name: ApplyAlphaChannel
  2327. // Desc: Restore the alpha information from the source bitmap to the
  2328. //       destination bitmap. GDI uses COLORREF structures which lack an alpha
  2329. //       channel, and draws everything as fully transparent. By using a 
  2330. //       separate bitmap to store opacity information, the alpha channel can
  2331. //       be restored.
  2332. //-----------------------------------------------------------------------------
  2333. HRESULT ApplyAlphaChannel( HBITMAP hbmpDest, HBITMAP hbmpSrc, BOOL bOpaque )
  2334. {
  2335.     HRESULT        hr          = S_OK;
  2336.     BITMAP         bmpInfoSrc  = {0}; 
  2337.     BITMAP         bmpInfoDest = {0};
  2338.     
  2339.    
  2340.     // Verify parameters
  2341.     if( NULL == hbmpDest || NULL == hbmpSrc )
  2342.         return DIERR_INVALIDPARAM;
  2343.  
  2344.     // Get the bitmap pixel data
  2345.     if( 0 == GetObject( hbmpSrc,  sizeof(BITMAP), &bmpInfoSrc ) )
  2346.         return E_FAIL;
  2347.  
  2348.     if( 0 == GetObject( hbmpDest, sizeof(BITMAP), &bmpInfoDest ) )
  2349.         return E_FAIL;
  2350.  
  2351.     // Cast the data pointers
  2352.     DWORD* pBitsSrc  = (DWORD*) bmpInfoSrc.bmBits;
  2353.     DWORD* pBitsDest = (DWORD*) bmpInfoDest.bmBits;
  2354.  
  2355.     // Syncronize bitmap pixel info
  2356.     GdiFlush();
  2357.  
  2358.     // For each pixel in the rect...
  2359.     for( int y=0; y < bmpInfoDest.bmHeight; y++ )
  2360.     {
  2361.         for( int x=0; x < bmpInfoDest.bmWidth; x++ )
  2362.         {
  2363.             if( *pBitsSrc )
  2364.             {
  2365.                 // The source bitmap contains information at this pixel, which 
  2366.                 // may signal full or partial opacity. If the passed bOpaque
  2367.                 // flag is set, the method should treat partially opaque pixels
  2368.                 // as being fully opaque. This is used when the user has selected
  2369.                 // a fully opaque background color and wants the resulting image
  2370.                 // to also be fully opaque.
  2371.                 *pBitsDest |= bOpaque ? ALPHA_MASK : ( GetBlue( *pBitsSrc ) << 24 );
  2372.             }  
  2373.             
  2374.             // Advance the pixel pointers.
  2375.             pBitsSrc++;
  2376.             pBitsDest++;
  2377.         }
  2378.     }
  2379.  
  2380.     return hr;
  2381. }
  2382.  
  2383.  
  2384.  
  2385.  
  2386. //-----------------------------------------------------------------------------
  2387. // Name: RestoreRect
  2388. // Desc: Restore the pixel data of an image for the given RECT
  2389. //-----------------------------------------------------------------------------
  2390. HRESULT RestoreRect( HBITMAP hbmpDest, CONST RECT* prcDest, LPBYTE pSrcPixels )
  2391. {
  2392.     BITMAP         bmpInfoDest = {0};
  2393.  
  2394.     // Verify parameters
  2395.     if( NULL == hbmpDest || NULL == pSrcPixels || NULL == prcDest )
  2396.         return DIERR_INVALIDPARAM;
  2397.  
  2398.     // Get the bitmap pixel data
  2399.     if( 0 == GetObject( hbmpDest, sizeof(BITMAP), &bmpInfoDest ) )
  2400.         return E_FAIL;
  2401.  
  2402.     // Cast the data pointers
  2403.     DWORD* pBitsSrc  = (DWORD*) pSrcPixels;
  2404.     DWORD* pBitsDest = (DWORD*) bmpInfoDest.bmBits;
  2405.  
  2406.     // Syncronize bitmap pixel info
  2407.     GdiFlush();
  2408.  
  2409.     // Advance the pixel pointers to the starting position
  2410.     pBitsDest += ( prcDest->top * bmpInfoDest.bmWidth ) + prcDest->left;
  2411.     pBitsSrc  += ( prcDest->top * bmpInfoDest.bmWidth ) + prcDest->left;
  2412.  
  2413.     // For each scanline in rcDest...
  2414.     for( int y = prcDest->top; y < prcDest->bottom; y++ )
  2415.     {
  2416.         CopyMemory( pBitsDest, pBitsSrc, sizeof(DWORD) * ( prcDest->right - prcDest->left ) );
  2417.         
  2418.         // Advance pointers
  2419.         pBitsDest += bmpInfoDest.bmWidth;
  2420.         pBitsSrc  += bmpInfoDest.bmWidth;
  2421.     
  2422.     }
  2423.  
  2424.     return DI_OK;
  2425. }
  2426.  
  2427.  
  2428.  
  2429.  
  2430. //-----------------------------------------------------------------------------
  2431. // Name: ApplyOverlay
  2432. // Desc: Use manual alpha blending to paste the overlay bitmap on top of the 
  2433. //       destination bitmap.
  2434. //-----------------------------------------------------------------------------
  2435. HRESULT ApplyOverlay( HBITMAP hbmpDest, CONST RECT* prcDest, HBITMAP hbmpSrc )
  2436. {
  2437.     BITMAP         bmpInfoSrc  = {0}; 
  2438.     BITMAP         bmpInfoDest = {0};
  2439.  
  2440.     // Verify parameters
  2441.     if( NULL == hbmpDest || NULL == hbmpSrc || NULL == prcDest )
  2442.         return DIERR_INVALIDPARAM;
  2443.  
  2444.     // Get the bitmap pixel data
  2445.     if( 0 == GetObject( hbmpSrc,  sizeof(BITMAP), &bmpInfoSrc ) )
  2446.         return E_FAIL;
  2447.  
  2448.     if( 0 == GetObject( hbmpDest, sizeof(BITMAP), &bmpInfoDest ) )
  2449.         return E_FAIL;
  2450.  
  2451.     // Cast the data pointers
  2452.     DWORD* pBitsSrc  = (DWORD*) bmpInfoSrc.bmBits;
  2453.     DWORD* pBitsDest = (DWORD*) bmpInfoDest.bmBits;
  2454.  
  2455.     // Syncronize bitmap pixel info
  2456.     GdiFlush();
  2457.  
  2458.     // Advance the destination pixel to the starting position
  2459.     pBitsDest += ( prcDest->top * bmpInfoDest.bmWidth ) + prcDest->left;
  2460.  
  2461.     // For each pixel...
  2462.     for( int y=0; y < bmpInfoSrc.bmHeight; y++ )
  2463.     {
  2464.         for( int x=0; x < bmpInfoSrc.bmWidth; x++ )
  2465.         {
  2466.             // calculate src and dest alpha
  2467.             if( ( *pBitsSrc & ALPHA_MASK ) == ALPHA_MASK )
  2468.             {
  2469.                 // Source pixel is completely opaque, have it replace the
  2470.                 // current destination pixel
  2471.                 *pBitsDest = *pBitsSrc;
  2472.             }            
  2473.             else if( ( *pBitsSrc & ALPHA_MASK ) == 0 )
  2474.             {
  2475.                 // Source pixel is completely transparent, do nothing
  2476.             }
  2477.             else
  2478.             {
  2479.             // This formula computes the blended component value:
  2480.                 // ( ALPHA * ( srcPixel - destPixel ) ) / 256 + destPixel
  2481.                 
  2482.                 DWORD dwMultiplier  = GetAlpha( *pBitsSrc );
  2483.  
  2484.                 // Decompose the image into color components
  2485.                 DWORD dwRed   = GetRed( *pBitsDest );
  2486.                 DWORD dwGreen = GetGreen( *pBitsDest );
  2487.                 DWORD dwBlue  = GetBlue( *pBitsDest );
  2488.  
  2489.  
  2490.                 // Calculate the component blend
  2491.                 dwRed   = ( dwMultiplier * (   GetRed( *pBitsSrc ) - dwRed   ) ) / 256 + dwRed;
  2492.                 dwGreen = ( dwMultiplier * ( GetGreen( *pBitsSrc ) - dwGreen ) ) / 256 + dwGreen;
  2493.                 dwBlue  = ( dwMultiplier * (  GetBlue( *pBitsSrc ) - dwBlue  ) ) / 256 + dwBlue;
  2494.                 
  2495.                 // Compose the blended pixel. The destination bitmap's original alpha
  2496.                 // value is preserved.
  2497.                 *pBitsDest = (*pBitsDest & ALPHA_MASK) | dwRed << 16 | dwGreen << 8 | dwBlue;
  2498.             }
  2499.  
  2500.             // Move to next pixel
  2501.             pBitsDest++;
  2502.             pBitsSrc++;
  2503.         }
  2504.  
  2505.         // Advance destination pointer
  2506.         pBitsDest += ( bmpInfoDest.bmWidth - bmpInfoSrc.bmWidth );
  2507.     }
  2508.  
  2509.     return DI_OK;
  2510. }
  2511.  
  2512.  
  2513.  
  2514.  
  2515. //-----------------------------------------------------------------------------
  2516. // Name: FillBackground
  2517. // Desc: Fills the background of the given bitmap with the provided fill color.
  2518. //       The background of the image is defined by the alpha channel.
  2519. //-----------------------------------------------------------------------------
  2520. HRESULT FillBackground( HBITMAP hbmpDest, D3DCOLOR Fill )
  2521. {
  2522.     BITMAP         bmpInfo     = {0}; 
  2523.     
  2524.     // Verify parameters
  2525.     if( NULL == hbmpDest )
  2526.         return DIERR_INVALIDPARAM;
  2527.  
  2528.     // Get the bitmap pixel data
  2529.     if( 0 == GetObject( hbmpDest, sizeof(BITMAP), &bmpInfo ) )
  2530.         return E_FAIL;
  2531.  
  2532.     // Cast the data pointers
  2533.     DWORD* pBits = (DWORD*) bmpInfo.bmBits;
  2534.  
  2535.     // Extract the component channels of the background color.
  2536.     DWORD dwBkAlpha = GetAlpha( Fill );
  2537.     DWORD dwBkRed   = GetRed( Fill );
  2538.     DWORD dwBkGreen = GetGreen( Fill );
  2539.     DWORD dwBkBlue  = GetBlue( Fill );
  2540.  
  2541.     // If the background color is defined as being completely opaque, the fill
  2542.     // method is performed a little differently. Normally, the per-pixel alpha
  2543.     // value is blended along with the color components, but this can result in
  2544.     // areas of the image which are partially transparent. If the provided fill
  2545.     // color is opaque, it's assumed that the user wishes to have the final
  2546.     // rendered surface completely opaque. If the provided background color is
  2547.     // partially transparent, then the alpha channel is blended to allow for
  2548.     // an antialiased border around the device image.
  2549.     BOOL  bBkOpaque = ( dwBkAlpha == 255 );
  2550.  
  2551.     // Syncronize bitmap pixel info
  2552.     GdiFlush();
  2553.  
  2554.     // For each pixel in the rect...
  2555.     for( int y=0; y < bmpInfo.bmHeight; y++ )
  2556.     {
  2557.         for( int x=0; x < bmpInfo.bmWidth; x++ )
  2558.         {
  2559.             if( (*pBits & ALPHA_MASK) == ALPHA_MASK )
  2560.             {
  2561.                 // Destination pixel is completely opaque, no fill needed.
  2562.             }            
  2563.             else if( (*pBits & ALPHA_MASK) == 0 )
  2564.             {
  2565.                 // Destination pixel is completely transparent, replace with
  2566.                 // the fill color.
  2567.                 *pBits = Fill;
  2568.             }
  2569.             else
  2570.             {
  2571.                 // This formula computes the blended component value:
  2572.                 // ( ALPHA * ( srcPixel - destPixel ) ) / 256 + destPixel
  2573.                 
  2574.                 DWORD dwMultiplier  = GetAlpha( *pBits );
  2575.  
  2576.                 // Calculate the component blend
  2577.                 DWORD dwAlpha = bBkOpaque ? 255 : 
  2578.                                 ( dwMultiplier * ( GetAlpha( *pBits ) - dwBkAlpha ) ) / 256 + dwBkAlpha;
  2579.                 DWORD dwRed   = ( dwMultiplier * (   GetRed( *pBits ) - dwBkRed   ) ) / 256 + dwBkRed;
  2580.                 DWORD dwGreen = ( dwMultiplier * ( GetGreen( *pBits ) - dwBkGreen ) ) / 256 + dwBkGreen;
  2581.                 DWORD dwBlue  = ( dwMultiplier * (  GetBlue( *pBits ) - dwBkBlue  ) ) / 256 + dwBkBlue;
  2582.                 
  2583.                 // Compose the final pixel color value
  2584.                 *pBits = dwAlpha << 24 | dwRed << 16 | dwGreen << 8 | dwBlue;
  2585.  
  2586.             }
  2587.  
  2588.             // Move to next pixel
  2589.             pBits++;
  2590.         }
  2591.     }
  2592.  
  2593.     return DI_OK;
  2594. }
  2595.  
  2596.  
  2597.  
  2598.  
  2599. //-----------------------------------------------------------------------------
  2600. // Name: DrawTooltip
  2601. // Desc: Draws tooltip text on the provided device contexts. The tooltip string
  2602. //       is drawn in relation to the RECT containing the truncated text, and 
  2603. //       using the given foreground, background, and border colors.
  2604. //-----------------------------------------------------------------------------
  2605. HRESULT DrawTooltip( HDC hdcRender, HDC hdcAlpha, LPCTSTR strTooltip, RECT* prcBitmap, 
  2606.                      RECT* prcTruncated, COLORREF crFore, COLORREF crBack, COLORREF crBorder )
  2607. {
  2608.     // Create the tooltip font. This should be highly readable at a small point
  2609.     // size, so a raster font has been chosen.
  2610.     HFONT hTipFont = NULL;
  2611.     LOGFONT lfTipFont = {0};
  2612.     SIZE sizeText = {0};
  2613.     
  2614.     lstrcpy( lfTipFont.lfFaceName, TEXT("MS Sans Serif") );
  2615.     lfTipFont.lfHeight = 8;
  2616.     lfTipFont.lfOutPrecision = OUT_RASTER_PRECIS;
  2617.     lfTipFont.lfQuality = PROOF_QUALITY;
  2618.     hTipFont = CreateFontIndirect( &lfTipFont );
  2619.  
  2620.     if( !hTipFont )
  2621.         hTipFont = (HFONT) GetStockObject( SYSTEM_FONT );
  2622.  
  2623.     HFONT hOldRenderFont = (HFONT) SelectObject( hdcRender, hTipFont );
  2624.     HFONT hOldAlphaFont = (HFONT) SelectObject( hdcAlpha, hTipFont );
  2625.  
  2626.     // How much screen space are we going to need?
  2627.     GetTextExtentPoint32( hdcRender, strTooltip, lstrlen( strTooltip ), &sizeText );
  2628.  
  2629.     // Position the rect right above the callout space
  2630.     RECT rcTooltip = { 0, 0, sizeText.cx, sizeText.cy };
  2631.     OffsetRect( &rcTooltip, prcTruncated->left + 2, prcTruncated->top - sizeText.cy - 2);
  2632.  
  2633.     InflateRect( &rcTooltip, 2, 2 );
  2634.  
  2635.     // Adjust the tooltip rect if it's beyond the screen edge
  2636.     if( rcTooltip.top < 0 )
  2637.         OffsetRect( &rcTooltip, 0, -rcTooltip.top );
  2638.  
  2639.     if( rcTooltip.right > prcBitmap->right )
  2640.         OffsetRect( &rcTooltip, prcBitmap->right - rcTooltip.right, 0 );
  2641.  
  2642.  
  2643.     // Draw tooltip 
  2644.     HBRUSH hOldRenderBrush = (HBRUSH) SelectObject( hdcRender, CreateSolidBrush( crBack ) );
  2645.     HPEN hOldRenderPen = (HPEN) SelectObject( hdcRender, CreatePen( PS_SOLID, 1, crBorder ) );
  2646.  
  2647.     COLORREF crOldRenderTextColor = SetTextColor( hdcRender, crFore );
  2648.  
  2649.     
  2650.     Rectangle( hdcRender, rcTooltip.left, rcTooltip.top, rcTooltip.right, rcTooltip.bottom );
  2651.     FillRect( hdcAlpha, &rcTooltip, (HBRUSH) GetStockObject( WHITE_BRUSH ) );
  2652.  
  2653.     InflateRect( &rcTooltip, -2, -2 );
  2654.     DrawText( hdcRender, strTooltip, lstrlen( strTooltip ), &rcTooltip, 0 );
  2655.     
  2656.     
  2657.  
  2658.     // Restore the DC state
  2659.     SelectObject( hdcRender, hOldRenderFont );
  2660.     SelectObject( hdcAlpha,  hOldAlphaFont );
  2661.     
  2662.     DeleteObject( (HBRUSH) SelectObject( hdcRender, hOldRenderBrush ) );
  2663.     DeleteObject( (HPEN)   SelectObject( hdcRender, hOldRenderPen ) );
  2664.  
  2665.     SetTextColor( hdcRender, crOldRenderTextColor );
  2666.  
  2667.     DeleteObject( hTipFont );
  2668.  
  2669.     return DI_OK;
  2670. }
  2671.  
  2672.  
  2673.  
  2674.  
  2675. //-----------------------------------------------------------------------------
  2676. // Name: CreateDIBSectionFromSurface
  2677. // Desc: Extract the pixel information from the provided surface and create
  2678. //       a new DIB Section.
  2679. //-----------------------------------------------------------------------------
  2680. HRESULT CreateDIBSectionFromSurface( LPDIRECT3DSURFACE9 pSurface, HBITMAP* phBitmap, SIZE* pSize )
  2681. {
  2682.     HRESULT         hr;
  2683.     D3DSURFACE_DESC d3dDesc;
  2684.     D3DLOCKED_RECT  d3dRect;
  2685.     LPBYTE          pDIBBits;
  2686.     LPBYTE          pSurfBits;
  2687.     BITMAPINFO      bmi = {0};
  2688.  
  2689.     // Get the surface info
  2690.     hr = pSurface->GetDesc( &d3dDesc );
  2691.     if( FAILED( hr ) )
  2692.         return hr;
  2693.  
  2694.     // Lock the surface
  2695.     hr = pSurface->LockRect( &d3dRect, NULL, 0 );
  2696.     if( FAILED( hr ) )
  2697.         return hr;
  2698.  
  2699.     pSurfBits = (LPBYTE) d3dRect.pBits;
  2700.  
  2701.     // Fill in the bitmap creation info
  2702.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  2703.     bmi.bmiHeader.biWidth = pSize ? pSize->cx : d3dDesc.Width;
  2704.     bmi.bmiHeader.biHeight = pSize ? -pSize->cy : ( - (int) d3dDesc.Height ); // Top-down DIB
  2705.     bmi.bmiHeader.biPlanes = 1;
  2706.     bmi.bmiHeader.biBitCount = 32;
  2707.     bmi.bmiHeader.biCompression = BI_RGB;
  2708.  
  2709.     
  2710.     HDC hdcMem = CreateCompatibleDC( NULL );
  2711.     if( NULL == hdcMem )
  2712.         return DIERR_OUTOFMEMORY;
  2713.  
  2714.     // Create the DIBSection
  2715.     *phBitmap = CreateDIBSection( hdcMem, &bmi, DIB_RGB_COLORS,( LPVOID* )&pDIBBits, NULL, 0 );
  2716.     DeleteDC( hdcMem );
  2717.     if( NULL == *phBitmap )
  2718.          return DIERR_OUTOFMEMORY;
  2719.  
  2720.     
  2721.     // Copy the bits
  2722.     for( UINT y=0; y < d3dDesc.Height; y++ )
  2723.     {
  2724.         CopyMemory( pDIBBits, pSurfBits, ( d3dDesc.Width * sizeof(DWORD) ) );
  2725.         pDIBBits += bmi.bmiHeader.biWidth * sizeof(DWORD);
  2726.         pSurfBits += d3dRect.Pitch;
  2727.     }
  2728.  
  2729.     return DI_OK;
  2730. }
  2731.  
  2732.  
  2733.  
  2734.  
  2735.  
  2736. //-----------------------------------------------------------------------------
  2737. // Name: EnumDeviceObjectsCB
  2738. // Desc: Cycle through device objects, adding information to the passed 
  2739. //       CDIDevImage object when appropriate.
  2740. //-----------------------------------------------------------------------------
  2741. BOOL CALLBACK EnumDeviceObjectsCB( LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef )
  2742. {
  2743.     HRESULT hr;
  2744.  
  2745.     // Extract the passed pointer
  2746.     CDIDevImage *pDIDevImage = (CDIDevImage*) pvRef;
  2747.     CDIDIObject *pObject     = NULL;
  2748.  
  2749.     // Add the object to the list
  2750.     hr = pDIDevImage->AddObject( lpddoi->dwType );
  2751.     if( FAILED(hr) )
  2752.         return DIENUM_STOP;
  2753.  
  2754.     // Set the object's friendly name
  2755.     pObject = pDIDevImage->GetObject( lpddoi->dwType );
  2756.     if( pObject )
  2757.         pObject->SetName( lpddoi->tszName );
  2758.  
  2759.  
  2760.     return DIENUM_CONTINUE;
  2761. }
  2762.  
  2763.  
  2764.  
  2765.  
  2766. //-----------------------------------------------------------------------------
  2767. // Name: DidcvDirect3DSurface9Clone
  2768. // Desc: a clone surface
  2769. //-----------------------------------------------------------------------------
  2770. class DidcvDirect3DSurface9Clone : public IUnknown
  2771. {
  2772. private:
  2773.     int m_iRefCount;
  2774.     BYTE *m_pData;
  2775.     D3DSURFACE_DESC m_Desc;
  2776.  
  2777. public:
  2778.     DidcvDirect3DSurface9Clone() : m_pData( NULL ), m_iRefCount( 1 ) { }
  2779.     ~DidcvDirect3DSurface9Clone() { delete[] m_pData; }
  2780.  
  2781. public:     
  2782.     // IUnknown methods
  2783.     STDMETHOD( QueryInterface )( REFIID  riid, VOID  **ppvObj ) { return E_NOINTERFACE; }
  2784.     STDMETHOD_( ULONG,AddRef )() { return ++m_iRefCount; }
  2785.     STDMETHOD_( ULONG,Release )()
  2786.     {
  2787.         if( !--m_iRefCount )
  2788.         {
  2789.             delete this;
  2790.             return 0;
  2791.         }
  2792.         return m_iRefCount;
  2793.     }
  2794.  
  2795.     // IDirect3DResource9 methods
  2796.     STDMETHOD( GetDevice )( IDirect3DDevice9 **ppDevice ) { return E_FAIL; }
  2797.     STDMETHOD( SetPrivateData )( REFGUID riid, CONST VOID *pvData, DWORD cbData, DWORD   dwFlags ) { return E_FAIL; }
  2798.     STDMETHOD( GetPrivateData )( REFGUID riid, VOID* pvData, DWORD  *pcbData ) { return E_FAIL; }
  2799.     STDMETHOD( FreePrivateData )( REFGUID riid ) { return E_FAIL; }
  2800.     STDMETHOD( SetPriority )( DWORD PriorityNew ) { return E_FAIL; }
  2801.     STDMETHOD_( DWORD, GetPriority )() { return 0; }
  2802.     STDMETHOD( PreLoad )() { return E_FAIL; }
  2803.     STDMETHOD( GetType )() { return E_FAIL; }
  2804.     
  2805.     // IDirect3DSurface9 methods
  2806.     STDMETHOD( GetContainer )( REFIID riid, void **ppContainer ) { return E_FAIL; }
  2807.     STDMETHOD_( D3DSURFACE_DESC, GetDesc )() { return m_Desc; }     
  2808.     STDMETHOD( LockRect )( D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD dwFlags )
  2809.     {
  2810.         // Assume the entire surface is being locked.
  2811.         pLockedRect->Pitch = m_Desc.Width * 4;
  2812.         pLockedRect->pBits = m_pData;
  2813.         return S_OK;
  2814.     }
  2815.     STDMETHOD( UnlockRect )() { return S_OK; }
  2816.     STDMETHOD( GetDC )() { return E_FAIL; }
  2817.     STDMETHOD( ReleaseDC )() { return E_FAIL; }
  2818.  
  2819.     BOOL Create( int iWidth, int iHeight )
  2820.     {
  2821.         m_pData = new BYTE[iWidth * iHeight * 4];
  2822.         if( !m_pData ) return FALSE;
  2823.  
  2824.         m_Desc.Format = D3DFMT_A8R8G8B8;
  2825.         m_Desc.Type = D3DRTYPE_SURFACE;
  2826.         m_Desc.Usage = 0;
  2827.         m_Desc.Pool = D3DPOOL_SYSTEMMEM;
  2828.         m_Desc.MultiSampleType = D3DMULTISAMPLE_NONE;
  2829.         m_Desc.MultiSampleQuality = 0;
  2830.         m_Desc.Width = iWidth;
  2831.         m_Desc.Height = iHeight;
  2832.         return TRUE;
  2833.     }
  2834. };
  2835.  
  2836.  
  2837.  
  2838.  
  2839. //-----------------------------------------------------------------------------
  2840. // Name: GetCloneSurface
  2841. // Desc: Fake a Direct3D surface so we don't have to actually create a direct3d
  2842. //       device object.
  2843. //-----------------------------------------------------------------------------
  2844. IDirect3DSurface9* GetCloneSurface( int iWidth, int iHeight )
  2845. {
  2846.     DidcvDirect3DSurface9Clone *pSurf = new DidcvDirect3DSurface9Clone;
  2847.  
  2848.     if( !pSurf ) return NULL;
  2849.     if( !pSurf->Create( iWidth, iHeight ) )
  2850.     {
  2851.         delete pSurf;
  2852.         return NULL;
  2853.     }
  2854.  
  2855.     return( IDirect3DSurface9* )pSurf;
  2856. }